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

import java.util.Collection;

import javax.inject.Inject;

import de.ivu.elect.business.stimmeingabe.control.StimmeingabePlausiBuilder;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeGruppeStimmen;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeGruppeStimmenErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeKopfzahl;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeKopfzahlErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeListenkandidaturStimmenErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiFehlerart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiTyp;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;

public class DefaultDirektwahlStimmeingabePlausiBuilder extends AbstractErgebniseingangPlausiBuilder implements StimmeingabePlausiBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient DefaultDirektwahlKopfzahlPlausiBuilder kopfzahlPlausiBuilder;

  public DefaultDirektwahlStimmeingabePlausiBuilder() {
    super();
  }

  @Override
  public boolean isApplicable(Wahl wahl) {
    return CommonWahlart.BUERGERMEISTERWAHL.equalsWahlart(wahl);
  }

  @Override
  protected AbstractStimmeingabePlausiDefinitions getStimmeingabePlausiDefinitions(Ergebniseingang ergebniseingang) {
    return kopfzahlPlausiBuilder.getStimmeingabePlausiDefinitions(ergebniseingang);
  }

  @Override
  protected void fillStimmeingabePlausis(StimmeingabePlausiBuilderContext context, StimmeingabeKopfzahlErfassenModel kopfzahlErfassenModel,
      StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel, Collection<StimmeingabeListenkandidaturStimmenErfassenModel> listenkandidaturStimmenErfassenModels) {
    fillAllgemeinePlausis(context);
    fillKopfzahlPlausis(kopfzahlErfassenModel, context);
    fillGruppeStimmenPlausis(gruppeStimmenErfassenModel, kopfzahlErfassenModel, context);
  }

  protected void fillKopfzahlPlausis(StimmeingabeKopfzahlErfassenModel model, StimmeingabePlausiBuilderContext context) {
    kopfzahlPlausiBuilder.fillKopfzahlPlausis(model, context);
  }

  private void fillGruppeStimmenPlausis(StimmeingabeGruppeStimmenErfassenModel model, StimmeingabeKopfzahlErfassenModel kopfzahlModel, StimmeingabePlausiBuilderContext context) {
    fillGruppeStimmenKopfzahlenPlausis(model, kopfzahlModel, context);
    fillGruppeStimmenGueltigeUndUngueltigePlausis(model, context);
    fillGruppeStimmenVergleichVorlaeufigEndgueltigPlausis(model, context);
  }

  private void fillGruppeStimmenKopfzahlenPlausis(StimmeingabeGruppeStimmenErfassenModel model, StimmeingabeKopfzahlErfassenModel kopfzahlModel, StimmeingabePlausiBuilderContext context) {
    Stimmeingabe stimmeingabeUngueltigeDirektstimmen = model.getStimmeingabeGruppeUngueltigeDirektstimmen().orElse(null);

    if (stimmeingabeUngueltigeDirektstimmen != null) {
      Stimmeingabe stimmeingabeGueltigeDirektstimmen = model.getStimmeingabeGruppeGueltigeDirektstimmen().orElse(null);

      if (stimmeingabeGueltigeDirektstimmen != null && isWaehlerGesamtZuPlausibilisieren(kopfzahlModel)) {
        StimmeingabeKopfzahl waehlerGesamt = kopfzahlModel.getWaehlerGesamt();

        // Gültige + Ungültige = Wähler
        addPlausiKopfzahl(waehlerGesamt,
            new WaehlerGesamtAnzahlGleichGueltigeStimmenAnzahlPlusUngueltigeStimmenAnzahlPlausi(stimmeingabeGueltigeDirektstimmen, stimmeingabeUngueltigeDirektstimmen,
                findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.WAEHLER_GESAMT_ANZAHL_GLEICH_GUELTIGE_DIREKTSTIMMEN_ANZAHL_PLUS_UNGUELTIGE_DIREKTSTIMMEN_ANZAHL,
                    StimmeingabePlausiFehlerart.ERROR),
                getMessages()),
            context);
      }

      // max. 5 % Ungültige
      kopfzahlModel.getWaehlerGesamtStimmeingabe()
          .ifPresent(stimmeingabeWaehlerGesamt -> addPlausi(stimmeingabeUngueltigeDirektstimmen,
              new UngueltigeStimmenAnzahlKleinerGleichWaehlerGesamtAnzahlAnteilPlausi(stimmeingabeWaehlerGesamt,
                  findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.UNGUELTIGE_DIREKTSTIMMEN_ANZAHL_KLEINER_GLEICH_WAEHLER_GESAMT_ANZAHL_ANTEIL,
                      StimmeingabePlausiFehlerart.WARNING, new StimmeingabeAnzahlComparedToStimmeingabeAnzahlAnteilPlausiCustomData(0.05D)),
                  getMessages()),
              context));
    }
  }

  private void fillGruppeStimmenGueltigeUndUngueltigePlausis(StimmeingabeGruppeStimmenErfassenModel model, StimmeingabePlausiBuilderContext context) {
    if (model.hasStimmenGruppeGueltige()) {
      StimmeingabeGruppeStimmen stimmeingabeGueltigeStimmen = model.getStimmenGruppeGueltige();

      // Gültige > 0
      addPlausiDirektstimme(stimmeingabeGueltigeStimmen, new StimmeingabeAnzahlGroesserAnzahlPlausi(StimmeingabeAnzahlReference.SYSTEM_GRUPPE_GUELTIGE_DIREKTSTIMMEN,
          findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.GUELTIGE_DIREKTSTIMMEN_ANZAHL_GROESSER_NULL, StimmeingabePlausiFehlerart.WARNING), getMessages()), context);

      // Gültige = Summe aller Direktkandidatenstimmen
      addPlausiDirektstimme(stimmeingabeGueltigeStimmen,
          new GueltigeStimmenAnzahlGleichGruppeStimmenAnzahlenSummePlausi(model.getStimmeingabenPolitischeGruppen(),
              findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.GUELTIGE_DIREKTSTIMMEN_ANZAHL_GLEICH_GRUPPE_DIREKTSTIMMEN_ANZAHLEN_SUMME, StimmeingabePlausiFehlerart.ERROR),
              getMessages()),
          context);
    }
  }
}
