
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.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

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.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 {

  public static final String DEFAULT_ITEM_SEPARATOR = "; ";

  private ErgebnisKonfliktCustomDataFormatter() {
    super();
  }

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

    return collectDisplayNamePerKandidatur(messages, kandidaturen);
  }

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

    return collectDisplayNamePerKandidatur(messages, kandidaturen);
  }

  public static Map<PersonendatenPK, String> collectDisplayNamePerKandidatur(Messages messages, 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ägeb...
      beschreibungFct = kandidatur -> messages.getMessageForMessageKey("ergebnis.konflikt.customdata.kandidatur.beschreibung.wahlvorschlag.gebiet",
          extractWahlvorschlagDisplayName(kandidatur.getWahlvorschlag()), extractGebietDisplayName(kandidatur.getGebiet()));
    }

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

    return result;
  }

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

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

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

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

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

    return trimToEmpty(kandidatur.getFamiliennameUndVornameUndTitel());
  }

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

    return collectDisplayNamePerWahlvorschlag(messages, wahlvorschlaege);
  }

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

    return collectDisplayNamePerWahlvorschlag(messages, wahlvorschlaege);
  }

  public static Map<WahlvorschlagPK, String> collectDisplayNamePerWahlvorschlag(Messages messages, 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 -> messages.getMessageForMessageKey("ergebnis.konflikt.customdata.wahlvorschlag.beschreibung.gebiet", extractGebietDisplayName(wahlvorschlag.getGebiet()));

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

    return result;
  }

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

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

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

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

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

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

  public static String formatListenverbindungDisplayName(Listenverbindung listenverbindung, Messages messages) {
    if (listenverbindung == null) {
      return "";
    }

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

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

    return trimToEmpty(listenverbindung.getBezeichnung());
  }

  public static String formatPolitischeGruppeDisplayName(Gruppe gruppe, Messages messages) {
    if (gruppe == null) {
      return "";
    }

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

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

    return trimToEmpty(gruppe.getKurzname());
  }

  public static String formatGebietDisplayName(Gebiet gebiet, Messages messages) {
    if (gebiet == null) {
      return "";
    }

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

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

    return trimToEmpty(gebiet.getName());
  }
}
