
package de.ivu.elect.dokumente.ergebnis;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;
import static java.util.stream.Collectors.toCollection;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.IntStream;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentQueue;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.anschrift.entity.Anschrift;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.gruppe.entity.NlPolitischeGruppe;
import de.ivu.elect.business.kandidatur.control.NlStimmzettelFormatter;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.NlListenkandidatur;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.NlListe;
import de.ivu.elect.dokumente.gebiet.BasicGebietDokument;

public class NlKandidatStimmenDocument extends BaseDocument {

  private static final long serialVersionUID = 1L;

  @DocumentSimpleField("ID")
  public final Long id;

  @DocumentSimpleField(value = "isGewaehlt")
  public final Boolean isEndgueltigGewaehlt;

  @DocumentSimpleField(value = "isUeberVorzugGewaehlt")
  public final Boolean isUeberVorzugGewaehlt;

  @DocumentSimpleField("GesamteStimmenzahl")
  public final Long anzahlStimmen;

  @DocumentSimpleField("GesamteStimmenzahlGewichtet")
  public final Long anzahlStimmenGewichtetMitVoteValues;

  @DocumentSimpleField("Gruppe-Position-Relativ")
  public final Long gruppePositionRelativ; // ELECT-13544

  @DocumentSimpleField("Gruppe-Position-Vorgegeben")
  public final Long gruppePositionVorgegeben; // ELECT-13544

  @DocumentSimpleField("Listenname")
  public final String listenname; // ELECT-13544

  @DocumentSimpleField("Listenposition")
  public final Long listenposition;

  @DocumentSimpleField("StimmzettelNamenFormatiert")
  public final String nameAufStimmzettelFormatted;

  @DocumentQueue(value = "StimmenProGebiet", elementClass = Long.class)
  public final LinkedList<Long> kandidatStimmenProGebiet;

  @DocumentQueue(value = "StimmenProGebietGewichtet", elementClass = Long.class)
  public final LinkedList<Long> kandidatStimmenProGebietGewichtetMitVoteValues;

  @DocumentSimpleField(value = "Wohnort")
  public final String wohnort;

  @DocumentSimpleField(value = "WohnortMitStaat")
  public final String wohnortMitStaat;

  @DocumentSimpleField(value = "WohnortMitStaatNichtNiederlande")
  public final String wohnortMitStaatNichtNiederlande;

  @DocumentSimpleField(value = "Rang")
  public final Long rang;

  @DocumentSimpleField(value = "isGewaehltAufStel")
  public final Boolean isAufStelGewaehlt;

  @DocumentSimpleField(value = "Stel-Nummer")
  public final Integer stelnummer;

  @DocumentSimpleField(value = "Wahlkreis-Nummer")
  public final String gebietsnummer;

  @DocumentSimpleField(value = "Wahlkreis-Name")
  public final String gebietsname;

  @DocumentSimpleField(value = "GewaehltIn-StelOderWahlkreis-Art")
  public final String gewaehltInArt;

  @DocumentSimpleField(value = "GewaehltIn-StelOderWahlkreis-Nummer")
  public final String gewaehltIn;

  @DocumentSimpleField(value = "GewaehltIn-StelOderWahlkreis-Name")
  public final String gewaehltInName;

  private final Listenkandidatur listenkandidatur;

  public NlKandidatStimmenDocument(NlErgebnisDatenCustomDataDocumentContext context, Gewaehlt gewaehlt, StimmzettelFormatter stimmzettelFormatter, Long anzahlStimmen,
      Long anzahlStimmenGewichtetMitVoteValues, LinkedList<Long> kandidatStimmenProGebiet, LinkedList<Long> kandidatStimmenProGebietGewichtetMitVoteValues, boolean isUeberVorzugGewaehlt) {
    super();

    this.listenkandidatur = castTo(gewaehlt.getKandidatur(), Listenkandidatur.class);

    this.id = this.listenkandidatur.getId();

    if (isKandidatAufEinzelnenGebiet(kandidatStimmenProGebiet)) {
      // Nur die gesamte Stimmenzahlen der Kandidaten werden in der Tabelle angezeigt
      this.kandidatStimmenProGebiet = NlKandidatStimmenDocument.createEmptyAnzahlenStimmen(kandidatStimmenProGebiet);
      this.kandidatStimmenProGebietGewichtetMitVoteValues = this.kandidatStimmenProGebiet;
    } else {
      this.kandidatStimmenProGebiet = kandidatStimmenProGebiet;
      this.kandidatStimmenProGebietGewichtetMitVoteValues = kandidatStimmenProGebietGewichtetMitVoteValues;
    }

    if (stimmzettelFormatter instanceof NlStimmzettelFormatter) {
      this.nameAufStimmzettelFormatted = ((NlStimmzettelFormatter) stimmzettelFormatter).formatKandidaturNamenInDokument(this.listenkandidatur);
    } else {
      this.nameAufStimmzettelFormatted = stimmzettelFormatter.formatKandidaturNamen(this.listenkandidatur);
    }

    this.anzahlStimmen = anzahlStimmen;
    this.anzahlStimmenGewichtetMitVoteValues = anzahlStimmenGewichtetMitVoteValues;

    Liste liste = this.listenkandidatur.getListe();
    NlPolitischeGruppe nlPolitischeGruppe = new NlPolitischeGruppe(liste.getGruppe());

    this.gruppePositionRelativ = nlPolitischeGruppe.getRelativePosition();
    this.gruppePositionVorgegeben = nlPolitischeGruppe.getVorgegebenePosition();

    this.listenname = NlListe.getName(liste);
    this.listenposition = this.listenkandidatur.getRelativePosition();

    NlListenkandidatur nlListenkandidatur = new NlListenkandidatur(this.listenkandidatur);
    Anschrift wohnanschrift = nlListenkandidatur.getWohnanschrift();
    String wohnanschriftStaat = trimToEmpty(wohnanschrift.getStaat());

    this.wohnort = trimToEmpty(wohnanschrift.getOrt());
    this.wohnortMitStaat = trimToEmpty(this.wohnort + (isNotBlank(wohnanschriftStaat) ? " (" + wohnanschriftStaat + ")" : ""));
    this.wohnortMitStaatNichtNiederlande = nlListenkandidatur.isWohnanschriftInNiederlande() ? this.wohnort : this.wohnortMitStaat;

    this.rang = gewaehlt.getRang();
    this.isEndgueltigGewaehlt = gewaehlt.getGewaehltStatus().isGewaehlt();
    this.isUeberVorzugGewaehlt = isUeberVorzugGewaehlt;

    Optional<Integer> stelNummerIfPresent = NlListe.getStelNummerWas(liste);

    if (stelNummerIfPresent.isPresent()) {
      Integer stelNummer = stelNummerIfPresent.get();

      this.isAufStelGewaehlt = true;

      this.stelnummer = stelNummer;

      this.gebietsnummer = null;
      this.gebietsname = null;

      this.gewaehltInArt = "Stel";
      this.gewaehltIn = this.gewaehltInArt + " " + this.stelnummer;
      this.gewaehltInName = this.gewaehltInArt + " " + this.stelnummer;
    } else {
      BasicGebietDokument wahlkreisDokument = new BasicGebietDokument(context.getWasElectContext(), gewaehlt.getGebiet());

      this.isAufStelGewaehlt = false;

      this.stelnummer = null;

      this.gebietsnummer = wahlkreisDokument.nummer;
      this.gebietsname = wahlkreisDokument.name;

      this.gewaehltInArt = "Kieskring";
      this.gewaehltIn = this.gewaehltInArt + " " + this.gebietsnummer;
      this.gewaehltInName = this.gebietsname; // ELECT-13664, OHNE "Kieskring"...
    }
  }

  public Listenkandidatur getListenkandidatur() {
    return listenkandidatur;
  }

  private boolean isKandidatAufEinzelnenGebiet(LinkedList<Long> kandidatStimmenProGebiet) {
    return kandidatStimmenProGebiet.stream().filter(Objects::nonNull).count() == 1;
  }

  public static LinkedList<Long> createEmptyAnzahlenStimmen(LinkedList< ? > values) {
    return IntStream.range(0, values.size()).<Long> mapToObj(ignored -> null).collect(toCollection(LinkedList::new));
  }
}
