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

import java.util.Collection;
import java.util.Objects;

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

import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Ergebnisart;
import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.control.EntityMitWurzelgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangStatus;
import de.ivu.elect.business.stimmeingabe.boundary.LetzterEingangLoader;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingabestatus;
import de.ivu.elect.business.stimmeingabe.entity.ErgebniseingabestatuswechelPruefergebnis;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingangsart;
import de.ivu.elect.business.wahl.entity.Wahl;


import static de.ivu.elect.jee.entity.EntityUtil.castTo;

@Stateless
@Specializes
public class NlErgebniseingangStatus extends ErgebniseingangStatus {

  @Inject
  private transient GebietDAO gebietDAO;

  @Inject
  private transient LetzterEingangLoader letzterEingangLoader;

  public NlErgebniseingangStatus() {
    super();
  }

  public ErgebniseingabestatuswechelPruefergebnis isErgebniseingabestatusAbgeschlossenMoeglich(Ergebnis ergebnisNotAttached, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebietNotAttached) {
    Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = attach(wahldurchfuehrungsgebietNotAttached);

    if (wahldurchfuehrungsgebiet == null || wahldurchfuehrungsgebiet.hasUebergeordnetesGebiet()) {
      return ErgebniseingabestatuswechelPruefergebnis.NICHT_MOEGLICH; // Ergebniseingabestatus nur auf dem Wurzelgebiet setzen...
    }

    Ergebnis ergebnis = attach(ergebnisNotAttached);

    if (ergebnis == null || wahldurchfuehrungsgebiet.getErgebniseingabestatus(ergebnis).getFolgeStatus().stream().noneMatch(Ergebniseingabestatus::isAbgeschlossen)) {
      return ErgebniseingabestatuswechelPruefergebnis.NICHT_MOEGLICH;
    }

    for (Wahldurchfuehrungsgebiet erfassungsgebiet : wahldurchfuehrungsgebiet.getErfassungsgebieteUnterhalb(gebietDAO)) {
      Ergebnisart ergebnisart = ergebnis.getErgebnisart();

      if (!erfassungsgebiet.getErgebniseingabestatus(ergebnisart).isAusbleibend()) {
        if (!isInErgebnisUebernehmbar(erfassungsgebiet, ergebnisart)) {
          return ErgebniseingabestatuswechelPruefergebnis.NICHT_MOEGLICH;
        }
      }
    }

    return ErgebniseingabestatuswechelPruefergebnis.MOEGLICH;
  }

  protected boolean isInErgebnisUebernehmbar(Wahldurchfuehrungsgebiet erfassungsgebiet, Ergebnisart ergebnisart) {
    return letzterEingangLoader.bestimmeLetztenEingang(erfassungsgebiet.getWahl().getPk(), erfassungsgebiet.getPk(), konvert(ergebnisart))
        .isInErgebnisUebernehmbar();
  }

  private Ergebniseingangsart konvert(Ergebnisart ergebnisart) {
    if (ergebnisart.isEndgueltig()) {
      return Ergebniseingangsart.ENDGUELTIG;
    }
    return Ergebniseingangsart.VORLAEUFIG;
  }

  public boolean isErgebniseingabestatusAuswertungMoeglich(Ergebnis ergebnisNotAttached) {
    Ergebnis ergebnis = attach(ergebnisNotAttached);

    if (ergebnis == null) {
      return false;
    }

    Wahl wahl = ergebnis.getWahl();
    Wahldurchfuehrungsgebiet wurzelgebiet = getWurzelgebiet(wahl);

    if (wurzelgebiet == null) {
      return false;
    }

    Ergebniseingabestatus wurzelgebietErgebniseingabestatus = wurzelgebiet.getErgebniseingabestatus(ergebnis);

    return wurzelgebietErgebniseingabestatus.isEingabeBeendet(); // ELECT-9981
  }

  public boolean isErgebniseingabestatusExportMoeglich(Ergebnis ergebnisNotAttached, Collection<Ergebniseingabestatus> ergebniseingabestatusZuExportieren) {
    Ergebnis ergebnis = attach(ergebnisNotAttached);

    if (ergebnis == null || ergebniseingabestatusZuExportieren.isEmpty()) {
      return false;
    }

    Wahl wahl = ergebnis.getWahl();
    Wahldurchfuehrungsgebiet wurzelgebiet = getWurzelgebiet(wahl);

    if (wurzelgebiet == null) {
      return false;
    }

    Ergebniseingabestatus wurzelgebietErgebniseingabestatus = wurzelgebiet.getErgebniseingabestatus(ergebnis);

    return ergebniseingabestatusZuExportieren.stream().anyMatch(ergebniseingabestatus -> Objects.equals(ergebniseingabestatus, wurzelgebietErgebniseingabestatus));
  }

  @Nullable
  protected Wahldurchfuehrungsgebiet getWurzelgebiet(Wahl wahl) {
    if (wahl != null) {
      Gebiet wurzelgebiet = wahl.getWurzelgebiet(EntityMitWurzelgebietDAO.fromDao(gebietDAO));
      if (wurzelgebiet == null) {
        return null;
      }
      return castTo(wurzelgebiet, Wahldurchfuehrungsgebiet.class);
    }

    return null;
  }
}
