
package de.ivu.elect.business.ergebniskonflikt.entity;

import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.kandidatur.boundary.AbstractKandidaturDAO;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractWahlvorschlagDAO;
import de.ivu.elect.business.wahlvorschlag.entity.Listenverbindung;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagPK;
import de.ivu.elect.jee.faces.Messages;

public class ErgebnisKonfliktCustomDataFormatter implements Serializable {

  private static final long serialVersionUID = 1L;

  public static final String DEFAULT_ITEM_SEPARATOR = "; ";

  @Inject
  private transient Messages messages;

  @Inject
  private transient StimmzettelFormatter stimmzettelFormatter;

  public ErgebnisKonfliktCustomDataFormatter() {
    super();
  }

  public Map<PersonendatenPK, String> collectDisplayNamePerKandidatur(AbstractKandidaturDAO kandidaturDAO, Collection<PersonendatenPK> pks) {
    List<Kandidatur> kandidaturen = pks.stream().map(kandidaturDAO::findByPrimaryKey).collect(toList());

    return collectDisplayNamePerKandidatur(kandidaturen);
  }

  public Map<PersonendatenPK, String> collectDisplayNamePerKandidatur(Map<PersonendatenPK, Kandidatur> kandidaturPerPK, Collection<PersonendatenPK> pks) {
    List<Kandidatur> kandidaturen = pks.stream().map(kandidaturPerPK::get).filter(Objects::nonNull).collect(toList());

    return collectDisplayNamePerKandidatur(kandidaturen);
  }

  public Map<PersonendatenPK, String> collectDisplayNamePerKandidatur(Collection< ? extends Kandidatur> kandidaturen) {
    Map<PersonendatenPK, String> result = new HashMap<>();

    Function<Kandidatur, String> beschreibungFct = kandidatur -> "";

    if (kandidaturen.stream().map(Kandidatur::getGebiet).filter(Objects::nonNull).distinct().count() > 1) { // ELECT-12143, Kandidaturen aus verschiedenen Gebieten/Wahlvorschlägen...
      beschreibungFct = kandidatur -> getMessage("ergebnis.konflikt.customdata.kandidatur.beschreibung.wahlvorschlag.gebiet", extractPolitischeGruppeDisplayName(kandidatur.getGruppe()),
          extractGebietDisplayName(kandidatur.getGebiet()));
    } else if (kandidaturen.stream().map(Kandidatur::getGruppe).filter(Objects::nonNull).distinct().count() > 1) { // ELECTKOM-3050, Kandidaturen aus verschiedenen Wahlvorschlägen...
      beschreibungFct = kandidatur -> getMessage("ergebnis.konflikt.customdata.kandidatur.beschreibung.wahlvorschlag", extractPolitischeGruppeDisplayName(kandidatur.getGruppe()));
    }

    for (Kandidatur kandidatur : kandidaturen) {
      result.put(kandidatur.getPk(), formatKandidaturDisplayName(kandidatur, beschreibungFct));
    }

    return result;
  }

  public String formatKandidaturDisplayName(Kandidatur kandidatur, Function<Kandidatur, String> beschreibungFct) {
    if (kandidatur == null) {
      return "";
    }

    String displayName = extractKandidaturDisplayName(kandidatur);
    String beschreibung = beschreibungFct.apply(kandidatur);

    if (isNotBlank(beschreibung)) {
      return getMessage("ergebnis.konflikt.customdata.kandidatur.format.beschreibung", displayName, beschreibung);
    }

    return getMessage("ergebnis.konflikt.customdata.kandidatur.format", displayName);
  }

  public String extractKandidaturDisplayName(Kandidatur kandidatur) {
    if (kandidatur == null) {
      return "";
    }

    // TODO getStimmzettelFormatter()#??? verwenden!!!
    return trimToEmpty(kandidatur.getTitelNamensbestandteileFamiliennameVorname());
  }

  public Map<WahlvorschlagPK, String> collectDisplayNamePerWahlvorschlag(AbstractWahlvorschlagDAO wahlvorschlagDAO, Collection<WahlvorschlagPK> pks) {
    List<Wahlvorschlag> wahlvorschlaege = pks.stream().map(wahlvorschlagDAO::findByPrimaryKey).collect(toList());

    return collectDisplayNamePerWahlvorschlag(wahlvorschlaege);
  }

  public Map<WahlvorschlagPK, String> collectDisplayNamePerWahlvorschlag(Map<WahlvorschlagPK, Wahlvorschlag> wahlvorschlagPerPK, Collection<WahlvorschlagPK> pks) {
    List<Wahlvorschlag> wahlvorschlaege = pks.stream().map(wahlvorschlagPerPK::get).filter(Objects::nonNull).collect(toList());

    return collectDisplayNamePerWahlvorschlag(wahlvorschlaege);
  }

  public Map<WahlvorschlagPK, String> collectDisplayNamePerWahlvorschlag(Collection< ? extends Wahlvorschlag> wahlvorschlaege) {
    Map<WahlvorschlagPK, String> result = new HashMap<>();

    // ELECT-12143 Wahlvorschläge aus verschiedenen Gebieten / WASDE-2092 Losentscheid zur Auswahl von Listen nicht eindeutig erkennbar
    Function<Wahlvorschlag, String> beschreibungFct = wahlvorschlag -> getMessage("ergebnis.konflikt.customdata.wahlvorschlag.beschreibung.gebiet",
        extractGebietDisplayName(wahlvorschlag.getGebiet()));

    for (Wahlvorschlag wahlvorschlag : wahlvorschlaege) {
      result.put(wahlvorschlag.getPk(), formatWahlvorschlagDisplayName(wahlvorschlag, beschreibungFct));
    }

    return result;
  }

  public String formatWahlvorschlagDisplayName(Wahlvorschlag wahlvorschlag, Function<Wahlvorschlag, String> beschreibungFct) {
    if (wahlvorschlag == null) {
      return "";
    }

    String displayName = extractWahlvorschlagDisplayName(wahlvorschlag);
    String beschreibung = beschreibungFct.apply(wahlvorschlag);

    if (isNotBlank(beschreibung)) {
      return getMessage("ergebnis.konflikt.customdata.wahlvorschlag.format.beschreibung", displayName, beschreibung);
    }

    return getMessage("ergebnis.konflikt.customdata.wahlvorschlag.format", displayName);
  }

  public String extractWahlvorschlagDisplayName(Wahlvorschlag wahlvorschlag) {
    if (wahlvorschlag == null || wahlvorschlag.getGruppe() == null) {
      return "";
    }

    return defaultIfBlank(wahlvorschlag.getKennwort(), trimToEmpty(wahlvorschlag.getGruppe().getKurzname()));
  }

  public String formatListenverbindungDisplayName(Listenverbindung listenverbindung) {
    if (listenverbindung == null) {
      return "";
    }

    return getMessage("ergebnis.konflikt.customdata.listenverbindung.displayname", extractListenverbindungDisplayName(listenverbindung));
  }

  public String extractListenverbindungDisplayName(Listenverbindung listenverbindung) {
    if (listenverbindung == null) {
      return "";
    }

    return trimToEmpty(listenverbindung.getBezeichnung());
  }

  public String formatPolitischeGruppeDisplayName(Gruppe gruppe) {
    if (gruppe == null) {
      return "";
    }

    return getMessage("ergebnis.konflikt.customdata.politischegruppe.displayname", extractPolitischeGruppeDisplayName(gruppe), gruppe.getName(), gruppe.getSchluessel());
  }

  public String extractPolitischeGruppeDisplayName(Gruppe gruppe) {
    if (gruppe == null) {
      return "";
    }

    return trimToEmpty(gruppe.getKurzname());
  }

  public String formatGebietDisplayName(Gebiet gebiet) {
    if (gebiet == null) {
      return "";
    }

    return getMessage("ergebnis.konflikt.customdata.gebiet.displayname", extractGebietDisplayName(gebiet));
  }

  public String extractGebietDisplayName(Gebiet gebiet) {
    if (gebiet == null) {
      return "";
    }

    return trimToEmpty(gebiet.getName());
  }

  public String getMessage(Enum< ? > typ, Object... params) {
    return getMessages().lokalisiere(typ, params);
  }

  public String getMessage(String msgKey, Object... params) {
    return getMessages().getMessageForMessageKey(msgKey, params);
  }

  protected Messages getMessages() {
    return messages;
  }

  protected StimmzettelFormatter getStimmzettelFormatter() {
    return stimmzettelFormatter;
  }
}
