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

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

import javax.annotation.Nonnull;

import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiKonfiguration;
import de.ivu.elect.jee.faces.Messages;

public class KommunalListenwahlListenkandidaturListenstimmenAnzahlKleinerGleichTheoretischesMaximumPlausi extends AbstractListenkandidaturListenstimmenAnzahlComparedToTheoretischeAnzahlPlausi
    implements
      StimmeingabePlausiAnzahlComparedToTheoretischesMaximum {

  private final Long anzahlStimmenProWaehlerMaximal;

  private final Long anzahlStimmenProWaehlerProListenkandidaturMaximal;

  private final Stimmeingabe stimmeingabeWaehlerGesamt;

  private final Stimmeingabe stimmzetteleingabeUngueltigeListenstimmen;

  private final Collection<Stimmeingabe> stimmzetteleingabenGruppeNurEinzelnerWahlvorschlagUnveraendert;

  public KommunalListenwahlListenkandidaturListenstimmenAnzahlKleinerGleichTheoretischesMaximumPlausi(Long anzahlStimmenProWaehlerMaximal, Long anzahlStimmenProWaehlerProListenkandidaturMaximal,
      Long anzahlNennungen, boolean stimmzettelNurEinzelnerWahlvorschlagUnveraendertManuellAuszuzaehlen, Stimmeingabe stimmeingabeWaehlerGesamt, Stimmeingabe stimmzetteleingabeUngueltigeListenstimmen,
      Collection<Stimmeingabe> stimmzetteleingabenGruppeNurEinzelnerWahlvorschlagUnveraendert, Stimmeingabe stimmzetteleingabeGruppeNurEinzelnerWahlvorschlagUnveraendert,
      StimmeingabePlausiKonfiguration stimmeingabePlausiKonfiguration, Messages messages) {
    super(anzahlNennungen, stimmzettelNurEinzelnerWahlvorschlagUnveraendertManuellAuszuzaehlen, stimmzetteleingabeGruppeNurEinzelnerWahlvorschlagUnveraendert,
        new StimmeingabeAnzahlComparedToStimmeingabeAnzahlenPlausiDefinition(StimmeingabeAnzahlReference.LISTENKANDIDATUR_LISTENSTIMMEN, StimmeingabeAnzahlComparedToOperator.LESS_THAN_OR_EQUAL_TO,
            StimmeingabeAnzahlReference.SYSTEM_GRUPPE_WAEHLER_GESAMT, StimmeingabeAnzahlReference.SYSTEM_GRUPPE_UNGUELTIGE_LISTENSTIMMEN,
            StimmeingabeAnzahlReference.SYSTEM_GRUPPE_GUELTIGE_LISTENSTIMMEN_NUR_EINZELNER_WAHLVORSCHLAG_UNVERAENDERT,
            StimmeingabeAnzahlReference.GRUPPE_LISTENSTIMMEN_NUR_EINZELNER_WAHLVORSCHLAG_UNVERAENDERT),
        stimmeingabePlausiKonfiguration, messages);

    ListenkandidaturStimmenAnzahlComparedToTheoretischesMaximumByAnzahlStimmenProWaehlerProListenkandidaturPlausiCustomData stimmeingabePlausiKonfigurationCustomData = stimmeingabePlausiKonfiguration
        .getCustomData(ListenkandidaturStimmenAnzahlComparedToTheoretischesMaximumByAnzahlStimmenProWaehlerProListenkandidaturPlausiCustomData.class);

    this.anzahlStimmenProWaehlerMaximal = anzahlStimmenProWaehlerMaximal;
    this.anzahlStimmenProWaehlerProListenkandidaturMaximal = stimmeingabePlausiKonfigurationCustomData
        .getAnzahlStimmenProWaehlerProListenkandidaturMaximalOrDefault(anzahlStimmenProWaehlerProListenkandidaturMaximal);

    this.stimmeingabeWaehlerGesamt = stimmeingabeWaehlerGesamt;

    this.stimmzetteleingabeUngueltigeListenstimmen = stimmzetteleingabeUngueltigeListenstimmen;

    this.stimmzetteleingabenGruppeNurEinzelnerWahlvorschlagUnveraendert = stimmzetteleingabenGruppeNurEinzelnerWahlvorschlagUnveraendert;
  }

  @Override
  protected StimmeingabePlausiResult calculatePlausiResult(@Nonnull Stimmeingabe stimmeingabe) {
    if (isWaehlerBenannteListenkandidaturSonstige(stimmeingabe)) { // ELECT-9359
      Long anzahlWaehlerBenannteListenkandidaturenMaximal = getAnzahlStimmenProWaehlerMaximal();
      Long anzahlStimmenWaehlerBenannteListenkandidaturSonstigeMaximal = anzahlWaehlerBenannteListenkandidaturenMaximal * getAnzahlStimmenWahlvorschlagVeraendertMaximal();

      return calculatePlausiResult(stimmeingabe, Math.max(0D, getComparedToAnteil() * anzahlStimmenWaehlerBenannteListenkandidaturSonstigeMaximal));
    }

    return super.calculatePlausiResult(stimmeingabe);
  }

  @Override
  protected Long getComparedToValue() {
    return getAnzahlStimmenNurEinzelnerWahlvorschlagUnveraendert() + getAnzahlStimmenWahlvorschlagVeraendertMaximal();
  }

  private long getAnzahlStimmenWahlvorschlagVeraendertMaximal() {
    return getAnzahlStimmenProWaehlerProListenkandidaturMaximal() * getAnzahlStimmzettelWahlvorschlagVeraendert();
  }

  private Long getAnzahlStimmenProWaehlerMaximal() {
    return anzahlStimmenProWaehlerMaximal;
  }

  private Long getAnzahlStimmenProWaehlerProListenkandidaturMaximal() {
    return anzahlStimmenProWaehlerProListenkandidaturMaximal;
  }

  private Long getAnzahlWaehlerGesamt() {
    return fixNullToZero(stimmeingabeWaehlerGesamt);
  }

  private long getAnzahlStimmzettelWahlvorschlagVeraendert() {
    Long anzahlStimmzettelWahlvorschlagVeraendert = getAnzahlStimmzettelGueltig();
    anzahlStimmzettelWahlvorschlagVeraendert -= fixEmptyToZero(stimmzetteleingabenGruppeNurEinzelnerWahlvorschlagUnveraendert);

    return Math.max(0, anzahlStimmzettelWahlvorschlagVeraendert);
  }

  private Long getAnzahlStimmzettelGueltig() {
    return getAnzahlWaehlerGesamt() - getAnzahlStimmzettelUngueltig();
  }

  private Long getAnzahlStimmzettelUngueltig() {
    return fixNullToZero(stimmzetteleingabeUngueltigeListenstimmen);
  }

  @Override
  protected List<Object> getStimmeingabefehlerBeschreibungParameters(Stimmeingabe stimmeingabe) {
    List<Object> result = new ArrayList<>(super.getStimmeingabefehlerBeschreibungParameters(stimmeingabe));
    result.add(getAnzahlStimmenProWaehlerProListenkandidaturMaximal());
    result.add(getAnzahlStimmzettelWahlvorschlagVeraendert());

    return result;
  }
}
