
package de.ivu.elect.business.stimmeingabe.control;

import static org.apache.commons.lang3.StringUtils.defaultIfBlank;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;

import javax.inject.Inject;

import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangDAO;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingabestufe;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.ErgebniseingangErfasser;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabefehler;
import de.ivu.elect.jee.entity.EntityUtil;
import de.ivu.elect.jee.entity.tk.EntityTK;

public class ErgebniseingangEndstufeAusVorstufeCreate {

  @Inject
  protected transient ErgebniseingangDAO ergebniseingangDAO;

  @Inject
  protected transient ErgebniseingangKopieren ergebniseingangKopieren;

  @Inject
  protected transient NlStimmeingabefehlerFactory nlStimmeingabefehlerFactory;

  public ErgebniseingangEndstufeAusVorstufeCreate() {
    super();
  }

  public boolean containsAnyStimmeingabefehlerEndstufeSpezifisch(Ergebniseingang ergebniseingang) {
    return nlStimmeingabefehlerFactory.containsAnyStimmeingabefehlerEndstufeSpezifisch(ergebniseingang);
  }

  public Optional<Ergebniseingang> createErgebnisErgebniseingangEndstufeFallsZulaessig(ErgebniseingangErfasser erfasser, Ergebniseingang ergebniseingang) {
    Ergebniseingabestufe ergebniseingangErgebniseingabestufe = ergebniseingang.getErgebniseingabestufe();

    if (!ergebniseingang.isGueltig() || ergebniseingangErgebniseingabestufe.isInErgebnisUebernehmbar()) {
      return Optional.empty();
    }

    Ergebniseingang ergebniseingangVorstufe01 = null;
    Ergebniseingang ergebniseingangVorstufe02 = null;

    if (Ergebniseingabestufe.VORSTUFE_01.equals(ergebniseingangErgebniseingabestufe)) {
      ergebniseingangVorstufe01 = ergebniseingang;
      ergebniseingangVorstufe02 = findLetzterErgebniseingangInErgebniseingabestufeGueltig(ergebniseingang, Ergebniseingabestufe.VORSTUFE_02);
    } else if (Ergebniseingabestufe.VORSTUFE_02.equals(ergebniseingangErgebniseingabestufe)) {
      ergebniseingangVorstufe01 = findLetzterErgebniseingangInErgebniseingabestufeGueltig(ergebniseingang, Ergebniseingabestufe.VORSTUFE_01);
      ergebniseingangVorstufe02 = ergebniseingang;
    }

    if (ergebniseingangVorstufe01 == null || ergebniseingangVorstufe02 == null) {
      return Optional.empty();
    }

    Ergebniseingang ergebniseingangEndstufe = createErgebniseingangEndstufe(erfasser, ergebniseingangVorstufe02);

    List<Stimmeingabefehler> stimmeingabefehlerFuerUnterschiede = createStimmeingabefehlerFuerUnterschiede(ergebniseingangEndstufe, ergebniseingangVorstufe01);

    if (stimmeingabefehlerFuerUnterschiede.stream().anyMatch(Stimmeingabefehler::isMussFehler)) {
      ergebniseingangEndstufe.setUngueltigMussFehler();
    } else if (stimmeingabefehlerFuerUnterschiede.stream().anyMatch(Stimmeingabefehler::isKannFehler)) {
      ergebniseingangEndstufe.setGueltigKannFehler(); // ELECTVAPP-209
    }

    return Optional.of(ergebniseingangEndstufe);
  }

  private Ergebniseingang findLetzterErgebniseingangInErgebniseingabestufeGueltig(Ergebniseingang ergebniseingangAktuell, Ergebniseingabestufe ergebniseingabestufe) {
    return ergebniseingangAktuell.getWahldurchfuehrungsgebiet().getLetzterErgebniseingangInErgebniseingabestufeGueltig(ergebniseingangDAO, ergebniseingangAktuell.getErgebniseingangsart(),
        ergebniseingabestufe);
  }

  public Ergebniseingang createErgebniseingangEndstufe(ErgebniseingangErfasser erfasser, Ergebniseingang template) {
    Ergebniseingang ergebniseingang = ergebniseingangKopieren.kopiereErgebniseingang(erfasser, null, template.getErgebniseingangsart(), Ergebniseingabestufe.ENDSTUFE,
        template.getErgebniseingangsherkunft(), template, true);
    ergebniseingang.setErgebniseingangsfehlerstatus(null); // Erneut validieren, um bspw. ELECTVAPP-37, #15 anzuzeigen...

    return ergebniseingang;
  }

  protected List<Stimmeingabefehler> createStimmeingabefehlerFuerUnterschiede(Ergebniseingang ergebniseingangEndstufe, Ergebniseingang ergebniseingangVorstufe) {
    List<Stimmeingabefehler> result = new ArrayList<>();

    Map<EntityTK, Stimmeingabe> stimmeingabenEndstufe = EntityUtil.mappeNachKonkretestemTk(ergebniseingangEndstufe.getStimmeingaben());
    Map<EntityTK, Stimmeingabe> stimmeingabenVorstufe = EntityUtil.mappeNachKonkretestemTk(ergebniseingangVorstufe.getStimmeingaben());

    for (Entry<EntityTK, Stimmeingabe> stimmeingabeEndstufePerStimmeingabeTK : stimmeingabenEndstufe.entrySet()) {
      EntityTK stimmeingabeTK = stimmeingabeEndstufePerStimmeingabeTK.getKey();

      Stimmeingabe stimmeingabeEndstufe = stimmeingabeEndstufePerStimmeingabeTK.getValue();
      Stimmeingabe stimmeingabeVorstufe = stimmeingabenVorstufe.get(stimmeingabeTK);

      if (!oneEqualsAnother(stimmeingabeEndstufe, stimmeingabeVorstufe)) {
        result.add(nlStimmeingabefehlerFactory.createStimmeingabefehlerEndstufeSpezifischStimmeingabeAnzahlInVorstufenGleich(stimmeingabeEndstufe, stimmeingabeVorstufe));
      }
    }

    return result;
  }

  // ELECT-9994, ELECTVAPP-172
  protected boolean oneEqualsAnother(Stimmeingabe one, Stimmeingabe another) {
    if (one != null && another != null) {
      String anotherNormalized = defaultIfBlank(another.getAnzahlEingabe(), "0");

      if (one.hasAnzahlGroesserGleichNull()) {
        long anzahl = one.getAnzahl();

        if (another.hasAnzahlGroesserGleichNull()) {
          return anzahl == another.getAnzahl();
        }

        return Objects.equals(Long.toString(anzahl), anotherNormalized);
      }

      String oneNormalized = defaultIfBlank(one.getAnzahlEingabe(), "0");

      if (another.hasAnzahlGroesserGleichNull()) {
        return Objects.equals(oneNormalized, Long.toString(another.getAnzahl()));
      }

      return Objects.equals(oneNormalized, anotherNormalized);
    }

    return false;
  }
}
