
package de.ivu.elect.business.kandidatur.boundary;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.inject.Inject;

import de.ivu.elect.business.ergebnis.control.AbstractKumulierteStimmenSearch;
import de.ivu.elect.business.ergebnis.control.StimmenPool;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeTK;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.kandidatur.control.DirektkandidaturKumulierteStimmenByGebietPositionUndPositionImGebietComparator;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.DirektkandidaturKumulierteStimmen;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlvorschlag.boundary.DirektkandidatDAO;
import de.ivu.elect.business.wahlvorschlag.boundary.DirektkandidatExtendedDAO;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;

public class DirektkandidaturKumulierteStimmenSearch extends AbstractKumulierteStimmenSearch<DirektkandidaturKumulierteStimmenSearchParameters, DirektkandidaturKumulierteStimmen> {

  @Inject
  private transient DirektkandidaturExtendedDAO direktkandidaturExtendedDAO;


  public DirektkandidaturKumulierteStimmenSearch() {
    super();
  }

  @Override
  protected List<DirektkandidaturKumulierteStimmen> suche(Wahl wahl, Gebiet gebietSelected, Ergebnis ergebnisSelected, DirektkandidaturKumulierteStimmenSearchParameters searchParameters) {
    Map<GruppeTK, GruppeImGebiet> gruppeToGruppeImGebietMap = baueGruppeToGruppeImGebietMapFuerGebiet(wahl, gebietSelected);

    List<Direktkandidatur> direktkandidaturenImGebiet = bestimmeDirektkandidaturenImGebiet(gebietSelected);

    Map<Gruppe, List<Direktkandidat>> direktKandidatenProGruppe = direktkandidaturenImGebiet.stream().collect(Collectors
        .groupingBy(direktkandidatur -> direktkandidatur.getDirektkandidat().getGruppe(),
            Collectors.mapping(Direktkandidatur::getDirektkandidat, Collectors.toList())));

    StimmenPool stimmenPool = StimmenPool.createStimmenPool(stimmenExtendedDAO, ergebnisSelected);

    List<DirektkandidaturKumulierteStimmen> result = new ArrayList<>();

    EntityAufStimmzettelDaten entityAufStimmzettelDaten = getEntityAufStimmzettelDaten();

    for (Direktkandidatur direktkandidatur : direktkandidaturenImGebiet) {
      Long anzahlDirektstimmen = bestimmeAnzahlDirektstimmen(direktkandidatur, gebietSelected, stimmenPool, direktKandidatenProGruppe);
      Long positionImGebiet = bestimmePositionImGebiet(direktkandidatur, gruppeToGruppeImGebietMap);

      result.add(new DirektkandidaturKumulierteStimmen(entityAufStimmzettelDaten, gebietSelected, direktkandidatur, anzahlDirektstimmen, positionImGebiet));
    }

    return result;
  }

  private Map<GruppeTK, GruppeImGebiet> baueGruppeToGruppeImGebietMapFuerGebiet(Wahl wahl, Gebiet gebietSelected) {
    List<GruppeImGebiet> gruppenImGebietAufAusgewaehltemGebiet = bestimmeGruppenImGebietAufAusgewaehltemGebietSchnell(gebietSelected, findAlleWahlvorschlaege(wahl));

    Map<GruppeTK, GruppeImGebiet> gruppeToGruppeImGebietMap = new HashMap<>();
    for (GruppeImGebiet gruppeImGebiet : gruppenImGebietAufAusgewaehltemGebiet) {
      gruppeToGruppeImGebietMap.put(gruppeImGebiet.getGruppe().getGruppeTK(), gruppeImGebiet);
    }
    return gruppeToGruppeImGebietMap;
  }

  private Long bestimmePositionImGebiet(Direktkandidatur direktkandidatur, Map<GruppeTK, GruppeImGebiet> gruppeToGruppeImGebietMap) {
    GruppeImGebiet gruppeImGebiet = gruppeToGruppeImGebietMap.get(direktkandidatur.getGruppe().getGruppeTK());
    if (gruppeImGebiet == null) {
      return null;
    }
    return gruppeImGebiet.getRelativePositionAbgeleitet();
  }

  private Long bestimmeAnzahlDirektstimmen(Direktkandidatur direktkandidatur, Gebiet gebietSelected, StimmenPool stimmenPool, Map<Gruppe, List<Direktkandidat>> direktKandidatenProGruppe) {
    return getStimmenKumulierer().getSummeStimmenFuerDirektkandidaturAufGebietUndDarunter(direktkandidatur, gebietSelected, stimmenPool,
        x->direktKandidatenProGruppe.get(x));
  }

  private List<Direktkandidatur> bestimmeDirektkandidaturenImGebiet(Gebiet gebietSelected) {
    return kandidaturFilter.filterAufStimmzettelUndInGebiet(direktkandidaturExtendedDAO.findByWahlAndUngleichStatus(gebietSelected.getWahl(), KandidaturStatus.NICHT_ZUGELASSEN), gebietSelected);
  }

  @Override
  protected Comparator< ? super DirektkandidaturKumulierteStimmen> getDefaultComparator() {
    return new DirektkandidaturKumulierteStimmenByGebietPositionUndPositionImGebietComparator();
  }

}
