package de.ivu.elect.dokumente.ergebnis;

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.ergebnis.control.NlErgebnisDaten;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class ListenstimmenProGruppeZeileDocument extends BaseDocument {
  @DocumentQueue(value = "StimmenProListe", elementClass = Long.class)
  public final LinkedList<String> gruppeStimmenProListe;

  @DocumentSimpleField("AnzahlStimmenDerGruppe")
  public final Long anzahlStimmenDerGruppe;

  @DocumentSimpleField("Position")
  public final Long position;
  private final Map<String, Long> stimmenzahlProGebietsnummerMap;

  public ListenstimmenProGruppeZeileDocument(PolitischeGruppe gruppe, NlErgebnisDaten ergebnisDaten) {
    position = gruppe.getRelativePosition();

    stimmenzahlProGebietsnummerMap = createStimmenzahlProGebietMap(ergebnisDaten, ergebnisDaten.getListenDerGruppe(gruppe));

    anzahlStimmenDerGruppe = stimmenzahlProGebietsnummerMap.values().stream()
            .filter(Objects::nonNull)
            .reduce(Long::sum)
            .orElse(0L);

    gruppeStimmenProListe = createGruppeStimmenProListeList(ergebnisDaten);

  }

  public Optional<Long> getStimmenzahlFuerGebiet(Wahldurchfuehrungsgebiet gebiet) {
    return Optional.ofNullable(stimmenzahlProGebietsnummerMap.get(gebiet.getNummer()));
  }

  private LinkedList<String> createGruppeStimmenProListeList(NlErgebnisDaten ergebnisDaten) {
    return ergebnisDaten.getListenwahlgebieteSortiertNachNummer().stream()
            .map(g -> {
              Long stimmenzahlFuerGebiet = stimmenzahlProGebietsnummerMap.get(g.getNummer());
              if (stimmenzahlFuerGebiet != null) {
                return stimmenzahlFuerGebiet.toString();
              }
              return ".";
            }).collect(Collectors.toCollection(LinkedList::new));
  }

  private Map<String, Long> createStimmenzahlProGebietMap(NlErgebnisDaten ergebnisDaten, Collection<Liste> listenDerGruppe) {
    return ergebnisDaten.getListenwahlgebieteSortiertNachNummer().stream()
            .map(gebiet -> listenDerGruppe.stream()
                    .filter(liste -> liste.getGebiet().equals(gebiet))
                    .map(liste -> new SimpleImmutableEntry<>(gebiet.getNummer(), ergebnisDaten.getSummeListeListenstimmen(gebiet, Stimmabgabeart.GESAMT, liste)))
                    .findAny()
                    .orElse(new SimpleImmutableEntry<>(gebiet.getNummer(), null)))
            .collect(HashMap::new, (map, entry)->map.put(entry.getKey(), entry.getValue()), HashMap::putAll); //https://bugs.openjdk.java.net/browse/JDK-8148463
  }
}
