
package de.ivu.elect.presentation.stimmeingabe;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.stimmeingabe.boundary.NlDefaultListenwahlStimmeingabeErfassenModelBuilder;
import de.ivu.elect.business.stimmeingabe.boundary.NlDefaultListenwahlStimmeingabeGruppeStimmenModelBuilder;
import de.ivu.elect.business.stimmeingabe.boundary.NlStimmeingabeKopfzahlModelBuilder;
import de.ivu.elect.business.stimmeingabe.entity.NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.NlStimmeingabeKopfzahlErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeGruppeStimmen;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeKopfzahl;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeStimmen;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;

public class NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenLayout {

  private final Wahl wahl;

  private final Customer customer;

  private final NlStimmeingabeKopfzahlErfassenModel stimmeingabeKopfzahlErfassenModel;

  private final NlStimmeingabeKopfzahlModelBuilder stimmeingabeKopfzahlModelBuilder;

  private final NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenModel stimmeingabeGruppeStimmenErfassenModel;

  private final NlDefaultListenwahlStimmeingabeGruppeStimmenModelBuilder stimmeingabeGruppeStimmenModelBuilder;

  public NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenLayout(Customer customer, NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenView view) {
    this(customer, ((NlDefaultListenwahlStimmeingabeErfassenModelBuilder) view.getStimmeingabeKopfzahlErfassenModelBuilder()).getStimmeingabeKopfzahlModelBuilder(),
        (NlStimmeingabeKopfzahlErfassenModel) view.getStimmeingabeKopfzahlErfassenModel(),
        ((NlDefaultListenwahlStimmeingabeErfassenModelBuilder) view.getStimmeingabeGruppeStimmenErfassenModelBuilder()).getStimmeingabeGruppeStimmenModelBuilder(),
        (NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenModel) view.getStimmeingabeGruppeStimmenErfassenModel());
  }

  public NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenLayout(Customer customer, NlStimmeingabeKopfzahlModelBuilder stimmeingabeKopfzahlModelBuilder,
      NlStimmeingabeKopfzahlErfassenModel stimmeingabeKopfzahlErfassenModel, NlDefaultListenwahlStimmeingabeGruppeStimmenModelBuilder stimmeingabeGruppeStimmenModelBuilder,
      NlDefaultListenwahlStimmeingabeGruppeStimmenErfassenModel stimmeingabeGruppeStimmenErfassenModel) {
    super();

    this.wahl = stimmeingabeKopfzahlErfassenModel.getBezugGebiet().getWahl();
    this.customer = customer;

    this.stimmeingabeKopfzahlModelBuilder = stimmeingabeKopfzahlModelBuilder;
    this.stimmeingabeKopfzahlErfassenModel = stimmeingabeKopfzahlErfassenModel;

    this.stimmeingabeGruppeStimmenModelBuilder = stimmeingabeGruppeStimmenModelBuilder;
    this.stimmeingabeGruppeStimmenErfassenModel = stimmeingabeGruppeStimmenErfassenModel;
  }

  public List<StimmeingabeKopfzahl> collectStimmeingabenKopfzahlOberhalb() {
    List<StimmeingabeKopfzahl> result = new ArrayList<>();

    result.addAll(stimmeingabeKopfzahlModelBuilder.layoutModelStimmeingabeKopfzahlWahlberechtigte(stimmeingabeKopfzahlErfassenModel));

    if (isStimmeingabenKopfzahlOberhalbIncludeWaehler()) {
      result.addAll(collectStimmeingabenKopfzahlWaehler());
    }

    List<StimmeingabeKopfzahl> stimmeingabenKopfzahlenStimmzettelEingenommen = new ArrayList<>();

    if (NlWahlart.EERSTE_KAMER.equalsWahlart(wahl)) { // ELECT-9890
      if (stimmeingabeKopfzahlErfassenModel.hasStimmzettelEingenommenGesamt()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenGesamt());
      }

      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeBlanko()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeBlanko()));
      }

      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeUngueltige()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeUngueltige()));
      }

      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeGueltige()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeGueltige()));
      }
    } else {
      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeGueltige()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeGueltige()));
      }

      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeBlanko()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeBlanko()));
      }

      if (stimmeingabeGruppeStimmenErfassenModel.hasStimmenGruppeUngueltige()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(asStimmeingabeKopfzahl(stimmeingabeGruppeStimmenErfassenModel.getStimmenGruppeUngueltige()));
      }

      if (stimmeingabeKopfzahlErfassenModel.hasStimmzettelEingenommenGesamt()) {
        stimmeingabenKopfzahlenStimmzettelEingenommen.add(stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenGesamt());
      }
    }

    result.addAll(stimmeingabenKopfzahlenStimmzettelEingenommen);

    if (stimmeingabenKopfzahlenStimmzettelEingenommen.size() > 1 && stimmeingabeKopfzahlErfassenModel.hasStimmzettelEingenommenGesamt()) {
      StimmeingabeKopfzahl stimmeingabeKopfzahlStimmzettelEingenommenGesamt = stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenGesamt();
      stimmeingabeKopfzahlStimmzettelEingenommenGesamt.addRowStyleClass(StimmeingabeStimmen.STYLE_CLASS_SUM); // ELECTVAPP-100
    }

    return result;
  }

  private boolean isStimmeingabenKopfzahlOberhalbIncludeWaehler() {
    return !isStimmeingabenKopfzahlUnterhalbIncludeWaehler();
  }

  public List<StimmeingabeKopfzahl> collectStimmeingabenKopfzahlUnterhalb() {
    List<StimmeingabeKopfzahl> result = new ArrayList<>();

    if (isStimmeingabenKopfzahlUnterhalbIncludeWaehler()) {
      result.addAll(collectStimmeingabenKopfzahlWaehler());
    }

    return result;
  }

  private boolean isStimmeingabenKopfzahlUnterhalbIncludeWaehler() {
    return /* ELECTVAPP-179 */ !NlWahlart.isWasPSB(wahl, customer) && /* ELECT-9890 */ !NlWahlart.EERSTE_KAMER.equalsWahlart(wahl);
  }

  private List<StimmeingabeKopfzahl> collectStimmeingabenKopfzahlWaehler() {
    List<StimmeingabeKopfzahl> result = new ArrayList<>(stimmeingabeKopfzahlModelBuilder.layoutModelStimmeingabeKopfzahlWaehler(stimmeingabeKopfzahlErfassenModel));

    if (result.size() > 1 && stimmeingabeKopfzahlErfassenModel.hasWaehlerGesamt()) {
      StimmeingabeKopfzahl stimmeingabeKopfzahlWaehlerGesamt = stimmeingabeKopfzahlErfassenModel.getWaehlerGesamt();
      stimmeingabeKopfzahlWaehlerGesamt.addRowStyleClass(StimmeingabeStimmen.STYLE_CLASS_SUM); // ELECTVAPP-100
    }

    return result;
  }

  // ELECTVAPP-93
  public boolean isStimmeingabenKopfzahlStimmzettelEingenommenAbweichendExpanded() {
    if (isStimmeingabenKopfzahlStimmzettelEingenommenAbweichendErfasst()) {
      return true;
    }

    if (collectStimmeingabenKopfzahlStimmzettelEingenommenAbweichend().stream().anyMatch(StimmeingabeKopfzahl::hasStimmeingabefehler)) {
      return true;
    }

    Optional<Stimmeingabe> stimmzetteleingabeStimmzettelEingenommenGesamt = stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenGesamtStimmeingabe();

    if (stimmzetteleingabeStimmzettelEingenommenGesamt.isPresent()) {
      Collection<Stimmeingabe> stimmeingabenWaehlerGesamt = stimmeingabeKopfzahlErfassenModel.getWaehlerGesamtStimmeingaben();

      if (!stimmeingabenWaehlerGesamt.isEmpty() && stimmeingabenWaehlerGesamt.stream().mapToLong(Stimmeingabe::getAnzahl).sum() != stimmzetteleingabeStimmzettelEingenommenGesamt.get().getAnzahl()) {
        return true;
      }
    }

    return false;
  }

  public boolean isStimmeingabenKopfzahlStimmzettelEingenommenAbweichendErfasst() {
    return collectStimmeingabenKopfzahlStimmzettelEingenommenAbweichend().stream().anyMatch(stimmeingabeKopfzahl -> stimmeingabeKopfzahl.getAnzahl() > 0L);
  }

  public List<StimmeingabeKopfzahl> collectStimmeingabenKopfzahlStimmzettelEingenommenAbweichend() {
    List<StimmeingabeKopfzahl> result = new ArrayList<>();

    List<StimmeingabeKopfzahl> stimmeingabeKopfzahlenStimmzettelEingenommenAbweichend = stimmeingabeKopfzahlModelBuilder
        .layoutModelStimmeingabeKopfzahlStimmzettelEingenommenAbweichend(stimmeingabeKopfzahlErfassenModel);

    result.addAll(stimmeingabeKopfzahlenStimmzettelEingenommenAbweichend);

    if (stimmeingabeKopfzahlenStimmzettelEingenommenAbweichend.size() > 2 && stimmeingabeKopfzahlErfassenModel.hasStimmzettelEingenommenAbweichendZuviel()
        && stimmeingabeKopfzahlErfassenModel.hasStimmzettelEingenommenAbweichendZuwenig()) {
      StimmeingabeKopfzahl stimmeingabeKopfzahlStimmzettelEingenommenAbweichendZuviel = stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenAbweichendZuviel();
      stimmeingabeKopfzahlStimmzettelEingenommenAbweichendZuviel.addRowStyleClass(StimmeingabeStimmen.STYLE_CLASS_SUM); // ELECTVAPP-100

      StimmeingabeKopfzahl stimmeingabeKopfzahlStimmzettelEingenommenAbweichendZuwenig = stimmeingabeKopfzahlErfassenModel.getStimmzettelEingenommenAbweichendZuwenig();
      stimmeingabeKopfzahlStimmzettelEingenommenAbweichendZuwenig.addRowStyleClass(StimmeingabeStimmen.STYLE_CLASS_SUM); // ELECTVAPP-100
    }

    return result;
  }

  private StimmeingabeKopfzahl asStimmeingabeKopfzahl(StimmeingabeGruppeStimmen stimmeingabeGruppeStimmen) {
    return new StimmeingabeKopfzahl( //
        stimmeingabeGruppeStimmen.getKennung(), stimmeingabeGruppeStimmen.getBezeichnung(), //

        stimmeingabeGruppeStimmen.getStimmeingabeListenstimme(), stimmeingabeGruppeStimmen.getStimmeingabeListenstimmeKennung(), stimmeingabeGruppeStimmen.getStimmeingabeListenstimmeBezeichnung(), "",
        null, stimmeingabeGruppeStimmen.getStimmeingabefehlerListenstimmeLetzterErgebniseingang(), stimmeingabeGruppeStimmen.getStimmeingabeListenstimmeVergleich() //
    );
  }
}
