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

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

import javax.ejb.Stateless;
import javax.inject.Inject;

import de.ivu.elect.business.ergebnis.control.AbstractKumulierteStimmenSearch;
import de.ivu.elect.business.ergebnis.control.LasseAllesDurchStimmenFilter;
import de.ivu.elect.business.ergebnis.control.StimmenFilter;
import de.ivu.elect.business.ergebnis.control.StimmenPool;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.entity.AbstractGebietsgruppierung;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.stimmen.boundary.ReferendumStimmeLabelGenerator;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOption;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOptionKumulierteStimmen;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOptionKumulierteStimmenByGruppeImGebietPositionAbgeleitetAndReferendumOptionPositionComparator;

@Stateless
public class ReferendumOptionKumulierteStimmenSearch extends AbstractKumulierteStimmenSearch<ReferendumOptionKumulierteStimmenSearchParameters, ReferendumOptionKumulierteStimmen> {

  private static final Comparator< ? super ReferendumOptionKumulierteStimmen> DEFAULT_COMPARATOR = new ReferendumOptionKumulierteStimmenByGruppeImGebietPositionAbgeleitetAndReferendumOptionPositionComparator();

  @Inject
  private transient ReferendumStimmeLabelGenerator referendumStimmeLabelGenerator;

  public ReferendumOptionKumulierteStimmenSearch() {
    super();
  }

  @Override
  protected List<ReferendumOptionKumulierteStimmen> suche(Wahl wahl, Gebiet gebietSelected, Ergebnis ergebnisSelected, ReferendumOptionKumulierteStimmenSearchParameters searchParameters) {
    List<ReferendumOptionKumulierteStimmen> result = new ArrayList<>();

    EntityAufStimmzettelDaten entityAufStimmzettelDaten = getEntityAufStimmzettelDaten();

    StimmenFilter stimmenFilter;

    if (searchParameters.getGebietsgruppierung() == null) {
      stimmenFilter = LasseAllesDurchStimmenFilter.INSTANCE;
    } else {
      // ELECT-6422
      stimmenFilter = s -> AbstractGebietsgruppierung.getGebietsgruppierungFilter(gebietsgruppierungExtendedDAO.attach(searchParameters.getGebietsgruppierung())).test(s.getGebiet());
    }

    StimmenPool stimmenPool = StimmenPool.createStimmenPool(stimmenExtendedDAO, ergebnisSelected, stimmenFilter);
    Long waehlerAufGebiet = getStimmenKumulierer().getSummeWaehlerGesamtStimmenAufGebiet(stimmenPool, gebietSelected);

    List<GruppeImGebiet> gruppenImGebiet = bestimmeGruppenImGebietAufAusgewaehltemGebietSchnell(gebietSelected, findAlleWahlvorschlaege(wahl));

    for (GruppeImGebiet gruppeImGebiet : gruppenImGebiet) {
      if (gruppeImGebiet.isReferendumVorlage()) {
        long referendumVorlageSummeGueltigeStimmen = 0L;
        long referendumOptionenMaxPosition = -1L;

        String gruppeBezeichnung = referendumStimmeLabelGenerator.formatReferendumVorlageBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);

        Collection<ReferendumOption> referendumOptionen = gruppeImGebiet.getReferendumOptionenInUebergeordneterGebietshierarchie();

        for (ReferendumOption referendumOption : referendumOptionen) {
          Long referendumOptionStimmen = getStimmenKumulierer().getSummeStimmenFuerReferendumOptionAufGebietUndDarunter(referendumOption, gebietSelected, stimmenPool);

          String referendumOptionBezeichnung = referendumStimmeLabelGenerator.formatReferendumOptionStimmeAnzahlGueltigeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet,
              referendumOption);
          String referendumOptionKennung = referendumStimmeLabelGenerator.formatReferendumOptionStimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet,
              referendumOption);

          result.add(new ReferendumOptionKumulierteStimmen(referendumOption, gruppeBezeichnung, referendumOptionBezeichnung, referendumOptionKennung, referendumOptionStimmen));

          referendumVorlageSummeGueltigeStimmen += referendumOptionStimmen;
          referendumOptionenMaxPosition = Math.max(referendumOptionenMaxPosition, referendumOption.getPosition());
        }

        String referendumVorlageGueltigeKennung = getReferendumGueltigeStimmenKennung(referendumStimmeLabelGenerator, gruppeImGebiet, gruppenImGebiet, referendumOptionen);
        String referendumVorlageGueltigeBezeichnung = getReferendumGueltigeStimmenBezeichnung(referendumStimmeLabelGenerator, gruppeImGebiet, gruppenImGebiet, referendumOptionen);

        result.add(new ReferendumOptionKumulierteStimmen(gruppeImGebiet, referendumOptionenMaxPosition + 1L, gruppeBezeichnung, referendumVorlageGueltigeBezeichnung, referendumVorlageGueltigeKennung,
            referendumVorlageSummeGueltigeStimmen));

        long referendumVorlageUngueltigeStimmen = waehlerAufGebiet - referendumVorlageSummeGueltigeStimmen;

        String referendumVorlageUngueltigeKennung = getReferendumUngueltigeStimmenKennung(referendumStimmeLabelGenerator, gruppeImGebiet, gruppenImGebiet, referendumOptionen);
        String referendumVorlageUngueltigeBezeichnung = getReferendumUngueltigeStimmenBezeichnung(referendumStimmeLabelGenerator, gruppeImGebiet, gruppenImGebiet, referendumOptionen);

        result.add(new ReferendumOptionKumulierteStimmen(gruppeImGebiet, referendumOptionenMaxPosition + 2L, gruppeBezeichnung, referendumVorlageUngueltigeBezeichnung,
            referendumVorlageUngueltigeKennung, referendumVorlageUngueltigeStimmen));

        // TODO: gruppeImGebiet-Parameter auf falscher Gebietsebene?!?
      }
    }

    return result;
  }

  protected String getReferendumGueltigeStimmenBezeichnung(ReferendumStimmeLabelGenerator referendumStimmeLabelGenerator, GruppeImGebiet gruppeImGebiet, List<GruppeImGebiet> gruppenImGebiet,
      Collection<ReferendumOption> referendumOptionen) {

    for (GruppeImGebiet imGebiet : gruppenImGebiet) {
      if (isSystemGruppeGueltige(imGebiet)) {
        return imGebiet.getGruppe().getKurzname();
      }
    }

    return getMessage("gruppe.system.name.GUELTIGE");
  }

  protected String getReferendumGueltigeStimmenKennung(ReferendumStimmeLabelGenerator referendumStimmeLabelGenerator, GruppeImGebiet gruppeImGebiet, List<GruppeImGebiet> gruppenImGebiet,
      Collection<ReferendumOption> referendumOptionen) {
    return referendumStimmeLabelGenerator.formatReferendumOptionStimmeAnzahlGueltigeGesamtKennung(getEntityAufStimmzettelDaten(), gruppeImGebiet, gruppenImGebiet);
  }

  protected String getReferendumUngueltigeStimmenKennung(ReferendumStimmeLabelGenerator referendumStimmeLabelGenerator, GruppeImGebiet gruppeImGebiet, List<GruppeImGebiet> gruppenImGebiet,
      Collection<ReferendumOption> referendumOptionen) {
    return referendumStimmeLabelGenerator.formatReferendumOptionStimmeAnzahlUngueltigeGesamtKennung(getEntityAufStimmzettelDaten(), gruppeImGebiet, gruppenImGebiet);
  }

  protected String getReferendumUngueltigeStimmenBezeichnung(ReferendumStimmeLabelGenerator referendumStimmeLabelGenerator, GruppeImGebiet gruppeImGebiet, List<GruppeImGebiet> gruppenImGebiet,
      Collection<ReferendumOption> referendumOptionen) {
    for (GruppeImGebiet imGebiet : gruppenImGebiet) {
      if (isSystemGruppeUngueltige(imGebiet)) {
        return imGebiet.getGruppe().getKurzname();
      }
    }

    return getMessage("gruppe.system.name.UNGUELTIGE");
  }

  @Override
  protected Comparator< ? super ReferendumOptionKumulierteStimmen> getDefaultComparator() {
    return DEFAULT_COMPARATOR;
  }
}
