
package de.ivu.elect.dokumente.stimmeingabe;

import static java.util.Objects.nonNull;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.SortedMap;

import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentMethod;
import de.ivu.document.generator.template.annotations.DocumentParam;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.ergebnis.control.ErgebnisDatenQuorum;
import de.ivu.elect.dokumente.DokumentFormatter;
import de.ivu.elect.dokumente.wahlvorschlag.GruppeDokument;

/**
 * NOTE, Frage steht in Gruppe#getName...
 */
// Cf. ReferendumVorlageMitStimmergebnissenDocument!!!
public class ReferendumVorlageStimmenDocument extends AbstractStimmenDocument {

  private static final long serialVersionUID = 1L;

  @DocumentSimpleField("Position-Fortlaufend")
  public Long positionFortlaufend;

  @DocumentComplexField("Gruppe")
  public GruppeDokument gruppeDokument;

  @DocumentSimpleField("Stimmen-Gueltig")
  public Long stimmenGueltig;

  @DocumentSimpleField("Stimmen-Gueltig-Formatiert")
  public String stimmenGueltigFormatiert;

  @DocumentSimpleField("Kennung-Gueltig")
  public String kennungGueltig;

  @DocumentSimpleField("Bezeichnung-Gueltig")
  public String bezeichnungGueltig;

  @DocumentSimpleField("Stimmen-Ungueltig")
  public Long stimmenUngueltig;

  @DocumentSimpleField("Stimmen-Ungueltig-Formatiert")
  public String stimmenUngueltigFormatiert;

  @DocumentSimpleField("Kennung-Ungueltig")
  public String kennungUngueltig;

  @DocumentSimpleField("Bezeichnung-Ungueltig")
  public String bezeichnungUngueltig;

  @DocumentSimpleField("Kennung-Abgegeben")
  public String kennungAbgegeben;

  @DocumentSimpleField("Stimmen-Gesamt")
  public Long stimmen;

  @DocumentSimpleField("Stimmen-Gesamt-Formatiert")
  public String stimmenFormatiert;

  @DocumentSimpleField("Quorum/Prozenthuerde")
  public BigDecimal quorum; // ELECT-13212

  @DocumentSimpleField("Quorum/Prozenthuerde-Formatiert")
  public String quorumFormatiert; // ELECT-13212

  @DocumentRepeat(value = "ReferendumOptionen", elementClass = ReferendumOptionStimmenDocument.class, itemName = "referendumOption")
  public List<ReferendumOptionStimmenDocument> referendumOptionen = new ArrayList<>();

  @DocumentSimpleField("ReferendumOptionStimmenmehrheitVorhanden")
  public boolean referendumOptionStimmenmehrheitVorhanden; // ELECT-13212

  @DocumentComplexField("ReferendumOptionStimmenmehrheit")
  public ReferendumOptionStimmenDocument referendumOptionStimmenmehrheit; // ELECT-13212

  @DocumentSimpleField("ReferendumOptionenStimmengleichheitVorhanden")
  public boolean referendumOptionenStimmengleichheitVorhanden; // ELECT-13212

  @DocumentRepeat(value = "ReferendumOptionenStimmengleichheit", elementClass = ReferendumOptionStimmenDocument.class, itemName = "referendumOption")
  public List<ReferendumOptionStimmenDocument> referendumOptionenStimmengleichheit = new ArrayList<>(); // ELECT-13212

  public ReferendumVorlageStimmenDocument(boolean eingabenAnzahlenStimmenExcluded) {
    super(eingabenAnzahlenStimmenExcluded);
  }

  @DocumentMethod // ELECT-13212
  public boolean isQuorumErreicht(@DocumentParam("Grundwert") Long grundwert, @DocumentParam("Stimmen") Long anzahlStimmen) {
    return anzahlStimmen != null && anzahlStimmen > 0L && anzahlStimmen >= berechneAnzahlStimmenQuorumErreicht(grundwert);
  }

  @DocumentMethod // ELECT-13212
  public long berechneAnzahlStimmenQuorumErreicht(@DocumentParam("Grundwert") Long grundwert) {
    return ErgebnisDatenQuorum.calculateAnzahlQuorumErreicht(quorum, grundwert);
  }

  public void addToDocumentKumuliert(StimmeingabeDocumentContext context, CoreStimmeingabeDocumentBuilder stimmeingabeDocumentBuilder,
      ReferendumVorlageStimmenDocument referendumVorlageStimmenDocument) {
    super.addToDocumentKumuliert(context, stimmeingabeDocumentBuilder, referendumVorlageStimmenDocument);

    Locale locale = context.getLocale();

    referendumVorlageStimmenDocument.positionFortlaufend = positionFortlaufend;

    referendumVorlageStimmenDocument.gruppeDokument = gruppeDokument;

    referendumVorlageStimmenDocument.kennungGueltig = kennungGueltig;
    referendumVorlageStimmenDocument.bezeichnungGueltig = bezeichnungGueltig;
    referendumVorlageStimmenDocument.stimmenGueltig = aggregate(referendumVorlageStimmenDocument.stimmenGueltig, stimmenGueltig);
    referendumVorlageStimmenDocument.stimmenGueltigFormatiert = DokumentFormatter.formatNumber(referendumVorlageStimmenDocument.stimmenGueltig, locale);

    referendumVorlageStimmenDocument.kennungUngueltig = kennungUngueltig;
    referendumVorlageStimmenDocument.bezeichnungUngueltig = bezeichnungUngueltig;
    referendumVorlageStimmenDocument.stimmenUngueltig = aggregate(referendumVorlageStimmenDocument.stimmenUngueltig, stimmenUngueltig);
    referendumVorlageStimmenDocument.stimmenUngueltigFormatiert = DokumentFormatter.formatNumber(referendumVorlageStimmenDocument.stimmenUngueltig, locale);

    referendumVorlageStimmenDocument.stimmen = aggregate(referendumVorlageStimmenDocument.stimmen, stimmen);
    referendumVorlageStimmenDocument.stimmenFormatiert = DokumentFormatter.formatNumber(referendumVorlageStimmenDocument.stimmen, locale);

    referendumVorlageStimmenDocument.quorum = quorum;
    referendumVorlageStimmenDocument.quorumFormatiert = DokumentFormatter.formatProzent(referendumVorlageStimmenDocument.quorum, locale);

    referendumVorlageStimmenDocument.referendumOptionen = ReferendumOptionStimmenDocument.aggregate(context, stimmeingabeDocumentBuilder, referendumVorlageStimmenDocument.referendumOptionen, referendumOptionen);
    referendumVorlageStimmenDocument.referendumOptionStimmenmehrheit = referendumOptionStimmenmehrheit;
    referendumVorlageStimmenDocument.referendumOptionStimmenmehrheitVorhanden = referendumVorlageStimmenDocument.referendumOptionStimmenmehrheit != null;
    referendumVorlageStimmenDocument.referendumOptionenStimmengleichheit = ReferendumOptionStimmenDocument.aggregate(context, stimmeingabeDocumentBuilder, referendumVorlageStimmenDocument.referendumOptionenStimmengleichheit, referendumOptionenStimmengleichheit);
    referendumVorlageStimmenDocument.referendumOptionenStimmengleichheitVorhanden = !referendumVorlageStimmenDocument.referendumOptionenStimmengleichheit.isEmpty();
  }

  public static List<ReferendumVorlageStimmenDocument> aggregate(StimmeingabeDocumentContext context, CoreStimmeingabeDocumentBuilder stimmeingabeDocumentBuilder,
      List<ReferendumVorlageStimmenDocument> targets, List<ReferendumVorlageStimmenDocument> sources) {
    SortedMap<Object, ReferendumVorlageStimmenDocument> targetPerKey = collectStimmenDocumentToAggregatePerTk(targets);

    for (ReferendumVorlageStimmenDocument source : sources) {
      Object tk = source.getTk();

      if (nonNull(tk)) {
        targetPerKey.putIfAbsent(tk, stimmeingabeDocumentBuilder.createReferendumVorlageStimmenDocument(context));
        source.addToDocumentKumuliert(context, stimmeingabeDocumentBuilder, targetPerKey.get(tk));
      }
    }

    return new ArrayList<>(targetPerKey.values());
  }
}
