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

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.gebietsbaum.control.AWerteAktualisierer;
import de.ivu.elect.business.gebietsbaum.control.AWerteAktualisiererFactory;
import de.ivu.elect.business.gebietsbaum.entity.AbstractGebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.stimmeingabe.boundary.LetzterEingangLoader;
import de.ivu.elect.business.wahl.entity.Wahl;

@Stateless
public class AWerteReset implements Serializable {
  private static final long serialVersionUID = 1L;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient LetzterEingangLoader letzterEingangLoader;

  @Inject
  private transient AWerteAktualisiererFactory aWerteAktualisiererFactory;

  public void awerteReset(Gebiet gebietNotAttached) {
    awerteReset(gebietNotAttached, false);
  }

  public void awerteResetErfasst(Gebiet gebietNotAttached) {
    awerteReset(gebietNotAttached, true);

  }

  private void awerteReset(Gebiet gebietNotAttached, boolean erfassteGebieteAuch) {
    if (gebietNotAttached == null) {
      return;
    }
    Wahldurchfuehrungsgebiet oberstesGebiet = wahldurchfuehrungsgebietDAO.findByPrimaryKey(gebietNotAttached.getPk());
    Wahl wahl = oberstesGebiet.getWahl();

    List<Wahldurchfuehrungsgebiet> alleGebieteDerWahl = wahldurchfuehrungsgebietDAO.findByWahl(wahl);
    List<Wahldurchfuehrungsgebiet> gebieteZuruecksetzen = alleGebieteDerWahl.stream()
        .filter(oberstesGebiet::isInGebietshierarchieUebergeordnetesGebietVon).collect(
            Collectors.toList());

    List<Wahldurchfuehrungsgebiet> erfassungsgebiete = gebieteZuruecksetzen.stream().filter(AbstractGebiet::isErfassungsgebietLautGebietsart)
        .collect(Collectors.toList());

    for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : erfassungsgebiete) {
      if (isAktualisiereBestehendenDatenZulaessig(wahldurchfuehrungsgebiet, erfassteGebieteAuch)) {
        wahldurchfuehrungsgebiet.resetAWerte();
      }
    }

    AWerteAktualisierer aWerteAktualisierer = aWerteAktualisiererFactory.createAWerteAktualisierer(wahl);
    for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : erfassungsgebiete) {
      aWerteAktualisierer.aktualisiereAWerteFuerUebergeordneteGebieteVon(wahldurchfuehrungsgebiet);
    }
  }

  public boolean isAktualisiereBestehendenDatenZulaessig(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, boolean overrideErgebniseingang) {
    return wahldurchfuehrungsgebiet != null && wahldurchfuehrungsgebiet.isErfassungsgebietLautGebietsart() && overrideErgebniseingang || !letzterEingangLoader.hasAnyErgebniseingang(
        wahldurchfuehrungsgebiet.getWahl().getPk(), wahldurchfuehrungsgebiet.getPk());
  }

  @Nullable
  public Long getAnzahlGebieteOhneAwerteWennOberstesGebietAwerteVorhanden(GebietPK gebietPk) {
    Wahldurchfuehrungsgebiet gebiet = wahldurchfuehrungsgebietDAO.findByPrimaryKey(gebietPk);
    if (gebiet == null) {
      return null;
    }

    Wahldurchfuehrungsgebiet oberstesGebiet = findeOberstesGebiet(gebiet);
    if (!oberstesGebiet.hasAnyAnzahlWahlberechtigte()) {
      return null;
    }

    return wahldurchfuehrungsgebietDAO.findByWahl(oberstesGebiet.getWahl()).stream()
        .filter(wahldurchfuehrungsgebiet -> wahldurchfuehrungsgebiet.isUrnenwahlgebiet() && !wahldurchfuehrungsgebiet.hasAnyAnzahlWahlberechtigte()).count();
  }

  private Wahldurchfuehrungsgebiet findeOberstesGebiet(Gebiet gebiet) {
    if (gebiet.getUebergeordnetesGebiet() == null) {
      return gebiet.castTo(Wahldurchfuehrungsgebiet.class).getEntity();
    }
    return findeOberstesGebiet(gebiet.getUebergeordnetesGebiet());
  }

}
