package de.ivu.elect.was.exchange.gebietsbaum.mapper;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.Specializes;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.ergebnis.control.StimmergebnisDaten;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietFactory;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.stimmeingabe.entity.ErgebnisGueltigerEingang;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingangsart;
import de.ivu.elect.business.wahl.boundary.WasWahlImporter;
import de.ivu.elect.business.wahl.control.Wahldaten;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.exchange.gebietsbaum.mapper.GebietMapper;
import de.ivu.elect.interfaces.core.Gebiet;
import de.ivu.elect.interfaces.core.GebietReferenz;
import de.ivu.elect.was.exchange.stimmeingabe.WasStimmeingabeXMLExportMapper;
import de.ivu.elect.was.exchange.stimmeingabe.WasStimmeingabeXMLImportMapper;
import de.ivu.elect.was.exchange.wahl.mapper.WasHelperMapper;

@Specializes
public class WasGebietMapper extends GebietMapper {

  private static final Logger LOG = LoggerFactory.getLogger(WasGebietMapper.class);

  @Inject
  private transient WasStimmeingabeXMLExportMapper wasStimmeingabeXMLExportMapper;

  @Inject
  private transient WasStimmeingabeXMLImportMapper wasStimmeingabeXMLImportMapper;

  @Inject
  private transient WasHelperMapper wasHelperMapper;


  @Inject
  private transient WahldurchfuehrungsgebietFactory wahldurchfuehrungsgebietFactory;

  public Gebiet mappe(de.ivu.elect.business.gebietsbaum.entity.Gebiet gebietIntern, Wahldaten wahldatenIntern) {
    Gebiet gebietExtern = super.mapGebiet(gebietIntern);

    de.ivu.elect.interfaces.core.Wahldurchfuehrungsgebiet wahldurchfuehrungsgebietExtern = new de.ivu.elect.interfaces.core.Wahldurchfuehrungsgebiet();
    gebietExtern.setWahldurchfuehrungsgebiet(wahldurchfuehrungsgebietExtern);

    Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = gebietIntern.castTo(Wahldurchfuehrungsgebiet.class).getEntity();

    wahldurchfuehrungsgebietExtern.setBriefwahlInUrneErfassen(wahldurchfuehrungsgebiet.getBriefwahlInUrneErfassen());
    wahldurchfuehrungsgebietExtern.setEingabestatusEndgueltig(wasHelperMapper.mappe(wahldurchfuehrungsgebiet.getEingabestatusEndgueltig()));
    wahldurchfuehrungsgebietExtern.setEingabestatusVorlaeufig(wasHelperMapper.mappe(wahldurchfuehrungsgebiet.getEingabestatusVorlaeufig()));
    wahldurchfuehrungsgebietExtern.setErfassungsbesonderheit(wasHelperMapper.mappe(wahldurchfuehrungsgebiet.getErfassungsbesonderheit()));
    wahldurchfuehrungsgebietExtern.setAnzahlWahlberechtigteOhneWahlschein(wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteOhneWahlschein());
    wahldurchfuehrungsgebietExtern.setAnzahlWahlberechtigteMitWahlschein(wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteMitWahlschein());
    wahldurchfuehrungsgebietExtern
        .setAnzahlWahlberechtigteNichtImWaehlerverzeichnis(wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteNichtImWaehlerverzeichnis());
    wahldurchfuehrungsgebietExtern.setTextFuerPraesentation(wahldurchfuehrungsgebiet.getTextFuerPraesentation());

    // ELECT-12040
    if (wahldurchfuehrungsgebiet.getErfasstIn() != null) {
      wahldurchfuehrungsgebietExtern.setErfassenIn(mapperUtil
          .createGebietReferenz(wahldurchfuehrungsgebiet.getErfasstIn().getNummer(), wahldurchfuehrungsgebiet.getErfasstIn().getGebietsart().getName()));
    }

    if (wahldurchfuehrungsgebiet.getWahlartBeiAufteilung() != null) {
      wahldurchfuehrungsgebietExtern.setWahlartBeiAufteilung(wahldurchfuehrungsgebiet.getWahlartBeiAufteilung().getName());
    }

    if (wahldatenIntern instanceof StimmergebnisDaten) {
      StimmergebnisDaten stimmergebnisDaten = (StimmergebnisDaten) wahldatenIntern;

      // finde für das Gebiet den
      Set<Ergebniseingang> ergebniseingaenge = new HashSet<>();
      for (Ergebniseingangsart ergebniseingangsart : Ergebniseingangsart.values()) {
        ErgebnisGueltigerEingang ergebnisGueltigerEingang = stimmergebnisDaten.getLetzteErgebnisGueltigerEingang(ergebniseingangsart).get(gebietIntern);
        if (ergebnisGueltigerEingang != null) {
          ergebniseingaenge.add(ergebnisGueltigerEingang.getErgebniseingang()); // letzte gültiger
        }
        Ergebniseingang letzter = stimmergebnisDaten.getLetzteErgebniseingaenge(ergebniseingangsart).get(gebietIntern);
        if (letzter != null) {
          ergebniseingaenge.add(letzter); // letzter
        }

      }
      addErgebniseingaenge(wahldurchfuehrungsgebietExtern, ergebniseingaenge);
    }

    return gebietExtern;
  }

  private void addErgebniseingaenge(de.ivu.elect.interfaces.core.Wahldurchfuehrungsgebiet wahldurchfuehrungsgebietExtern, Set<Ergebniseingang> ergebniseingaenge) {
    ArrayList<Ergebniseingang> ergebniseingaengeSortiert = new ArrayList<>(ergebniseingaenge);
    ergebniseingaengeSortiert.sort(Comparator.comparing(Ergebniseingang::getEingangssequenznummer));
    wahldurchfuehrungsgebietExtern.setErfassteStimmen(wasStimmeingabeXMLExportMapper.mappe(ergebniseingaengeSortiert));
  }

  @Override
  protected void mapGebiet(Gebiet gebietExtern, de.ivu.elect.business.gebietsbaum.entity.Gebiet commonGebietIntern, Map<GebietReferenz,
      de.ivu.elect.business.gebietsbaum.entity.Gebiet> interneGebieteNachReferenz) {
    super.mapGebiet(gebietExtern, commonGebietIntern, interneGebieteNachReferenz);
    Wahldurchfuehrungsgebiet gebietIntern = (Wahldurchfuehrungsgebiet) commonGebietIntern;

    de.ivu.elect.interfaces.core.Wahldurchfuehrungsgebiet wahldurchfuehrungsgebietExtern = gebietExtern.getWahldurchfuehrungsgebiet();
    if (wahldurchfuehrungsgebietExtern != null) {
      gebietIntern.setBriefwahlInUrneErfassen(wahldurchfuehrungsgebietExtern.getBriefwahlInUrneErfassen());
      gebietIntern.setEingabestatusEndgueltig(wasHelperMapper.mappe(wahldurchfuehrungsgebietExtern.getEingabestatusEndgueltig()));
      gebietIntern.setEingabestatusVorlaeufig(wasHelperMapper.mappe(wahldurchfuehrungsgebietExtern.getEingabestatusVorlaeufig()));
      gebietIntern.setErfassungsbesonderheit(wasHelperMapper.mappe(wahldurchfuehrungsgebietExtern.getErfassungsbesonderheit()));
      gebietIntern.setAnzahlWahlberechtigteOhneWahlschein(wahldurchfuehrungsgebietExtern.getAnzahlWahlberechtigteOhneWahlschein());
      gebietIntern.setAnzahlWahlberechtigteMitWahlschein(wahldurchfuehrungsgebietExtern.getAnzahlWahlberechtigteMitWahlschein());
      gebietIntern.setAnzahlWahlberechtigteNichtImWaehlerverzeichnis(wahldurchfuehrungsgebietExtern.getAnzahlWahlberechtigteNichtImWaehlerverzeichnis());
      gebietIntern.setTextFuerPraesentation(wahldurchfuehrungsgebietExtern.getTextFuerPraesentation());

      if (wahldurchfuehrungsgebietExtern.getErfassenIn() != null) {
        de.ivu.elect.business.gebietsbaum.entity.Gebiet gebietInDemErfasstWird = interneGebieteNachReferenz.get(wahldurchfuehrungsgebietExtern.getErfassenIn());
        if (gebietInDemErfasstWird == null) {
          LOG.warn("Keine Gebiet zur Referenz gefunden! " + wahldurchfuehrungsgebietExtern.getErfassenIn());
        } else {
          gebietIntern.setErfasstIn(gebietInDemErfasstWird.castTo(Wahldurchfuehrungsgebiet.class).getEntity());
        }
      }

      if (StringUtils.isNotBlank(wahldurchfuehrungsgebietExtern.getWahlartBeiAufteilung())) {
        Wahlart wahlartBeiAufteilung = new Wahlart();
        wahlartBeiAufteilung.setName(wahldurchfuehrungsgebietExtern.getWahlartBeiAufteilung());
        gebietIntern.setWahlartBeiAufteilung(wahlartBeiAufteilung);
      }

      List<Ergebniseingang> ergebniseingaenge = wasStimmeingabeXMLImportMapper.mappe(wahldurchfuehrungsgebietExtern.getErfassteStimmen());
      gebietIntern.addAdditionalData(WasWahlImporter.ERGEBNISEINGAENGE_KEY, ergebniseingaenge);
    }

  }

  @Override
  protected Wahldurchfuehrungsgebiet createEmptyGebietObject(Gebietsart gebietsartIntern) {
    return wahldurchfuehrungsgebietFactory.create();
  }
}
