
package de.ivu.elect.business.stimmeingabe.entity;

import static java.util.stream.Collectors.toList;
import static org.apache.deltaspike.core.util.ArraysUtils.asSet;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.BooleanSupplier;

import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.jee.exception.ElectCommonException;

public enum Ergebniseingabestatus {

  EINGABE_MOEGLICH(UseCasePermission.GEBIET_ERGEBNISEINGABESTATUS_SETZEN_EINGABE_MOEGLICH) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return getEingabeNichtMoeglichExceptionHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addWarnMessageEingabeNichtMoeglichHerkunftFalsch(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addInfoMessageEingabeUntergeordnetNichtMoeglichHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public String getIcon() {
      return "fa fa-pencil";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return asSet(GESPERRT, ABGESCHLOSSEN, AUSBLEIBEND);
    }

    @Override
    public boolean isEingabeBeendet() {
      return false;
    }

    @Override
    public boolean isEingabeMoeglichStatus() {
      return true;
    }

    @Override
    public boolean isEingabeMoeglich(Ergebniseingangsherkunft ergebniseingangsherkunft, BooleanSupplier eingangsherkunftIgnorieren) {
      return true;
    }
  },
  EINGABE_MOEGLICH_INTERN(UseCasePermission.OHNE) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return getEingabeNichtMoeglichExceptionHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addWarnMessageEingabeNichtMoeglichHerkunftFalsch(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addInfoMessageEingabeUntergeordnetNichtMoeglichHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public String getIcon() {
      return "fa-pencil-square-o";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return EINGABE_MOEGLICH.getFolgeStatus();
    }

    @Override
    public boolean isEingabeBeendet() {
      return EINGABE_MOEGLICH.isEingabeBeendet();
    }

    @Override
    public boolean isEingabeMoeglichStatus() {
      return true;
    }

    @Override
    public boolean isEingabeMoeglich(Ergebniseingangsherkunft ergebniseingangsherkunft, BooleanSupplier eingangsherkunftIgnorieren) {
      return EINGABE_MOEGLICH.isEingabeMoeglich(ergebniseingangsherkunft, eingangsherkunftIgnorieren)
              && ((ergebniseingangsherkunft != null && ergebniseingangsherkunft.isZulaessigAlsInterneQuelle()) || eingangsherkunftIgnorieren.getAsBoolean());
    }

    @Override
    public boolean isInternStatus() {
      return true;
    }
  },
  EINGABE_MOEGLICH_EXTERN(UseCasePermission.OHNE) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return getEingabeNichtMoeglichExceptionHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addWarnMessageEingabeNichtMoeglichHerkunftFalsch(this, ergebniseingangExceptionContext);
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      addInfoMessageEingabeUntergeordnetNichtMoeglichHerkunftFalsc(this, ergebniseingangExceptionContext);
    }

    @Override
    public String getIcon() {
      return "fa fa-pencil-square";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return EINGABE_MOEGLICH.getFolgeStatus();
    }

    @Override
    public boolean isEingabeBeendet() {
      return EINGABE_MOEGLICH.isEingabeBeendet();
    }

    @Override
    public boolean isEingabeMoeglichStatus() {
      return true;
    }

    @Override
    public boolean isEingabeMoeglich(Ergebniseingangsherkunft ergebniseingangsherkunft, BooleanSupplier eingangsherkunftIgnorieren) {
      return EINGABE_MOEGLICH.isEingabeMoeglich(ergebniseingangsherkunft, eingangsherkunftIgnorieren)
              && ((ergebniseingangsherkunft != null && ergebniseingangsherkunft.isZulaessigAlsExterneQuelle()) || eingangsherkunftIgnorieren.getAsBoolean());
    }

    @Override
    public boolean isExternStatus() {
      return true;
    }
  },
  GESPERRT(UseCasePermission.GEBIET_ERGEBNISEINGABESTATUS_SETZEN_GESPERRT) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return new ElectCommonException(MESSAGE_KEY_EINGABE_GESPERRT, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addWarnMessage(MESSAGE_KEY_EINGABE_GESPERRT, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addInfoMessage(MESSAGE_KEY_EINGABE_GESPERRT_UNTERGEORDNET, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public String getIcon() {
      return "fa fa-lock";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return asSet(EINGABE_MOEGLICH);
    }

    @Override
    public boolean isEingabeBeendet() {
      return false;
    }

    @Override
    public boolean isEigenerMessageKeyFuerUebergang() {
      return true;
    }

    @Override
    public boolean isGesperrt() {
      return true;
    }
  }, // Zurzeit keine Eingabe möglich

  ABGESCHLOSSEN(UseCasePermission.GEBIET_ERGEBNISEINGABESTATUS_SETZEN_ABGESCHLOSSEN) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return new ElectCommonException(MESSAGE_KEY_EINGABE_ABGESCHLOSSEN, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addWarnMessage(MESSAGE_KEY_EINGABE_ABGESCHLOSSEN, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addInfoMessage(MESSAGE_KEY_EINGABE_ABGESCHLOSSEN_UNTERGEORDNET, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public String getIcon() {
      return "fa fa-info-circle";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return asSet(EINGABE_MOEGLICH, FREIGEGEBEN);
    }

    @Override
    public boolean isAbgeschlossen() {
      return true;
    }

    @Override
    public boolean isEingabeBeendet() {
      return true;
    }
  },

  // Keine weiteren Eingabe mehr vorgesehen
  FREIGEGEBEN(UseCasePermission.GEBIET_ERGEBNISEINGABESTATUS_SETZEN_FREIGEGEBEN) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return new ElectCommonException(MESSAGE_KEY_EINGABE_FREIGEGEBEN, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addWarnMessage(MESSAGE_KEY_EINGABE_FREIGEGEBEN, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addInfoMessage(MESSAGE_KEY_EINGABE_FREIGEGEBEN_UNTERGEORDNET, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public String getIcon() {
      return "fa fa-check";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return asSet(ABGESCHLOSSEN);
    }

    @Override
    public boolean isEingabeBeendet() {
      return true;
    }
  },

  // WASDE-616 Dieses Gebiet nimmt nicht an der Ergebnisermittlung Teil (Kandidaten gestorben, etc...)
  AUSBLEIBEND(UseCasePermission.GEBIET_ERGEBNISEINGABESTATUS_SETZEN_AUSBLEIBEND) {

    @Override
    public ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      return new ElectCommonException(MESSAGE_KEY_EINGABE_AUSBLEIBEND, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addWarnMessage(MESSAGE_KEY_EINGABE_AUSBLEIBEND, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
      ergebniseingangExceptionContext.addInfoMessage(MESSAGE_KEY_EINGABE_AUSBLEIBEND_UNTERGEORDNET, ergebniseingangExceptionContext.getGebietDarstellung());
    }

    @Override
    public boolean isFuerGebietZurAuswahl(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
      return super.isFuerGebietZurAuswahl(wahldurchfuehrungsgebiet);
      // && wahldurchfuehrungsgebiet.isErfassungsgebiet() auskommentiert wegen ELECT-5685
    }

    @Override
    public boolean isGebietZaehltWeiterAlsErfassungsgebiet() {
      return false;
    }

    @Override
    public String getIcon() {
      return "fa fa-times-circle";
    }

    @Override
    public Set<Ergebniseingabestatus> getFolgeStatus() {
      return asSet(EINGABE_MOEGLICH);
    }

    @Override
    public boolean isEingabeBeendet() {
      return false;
    }

    @Override
    public boolean isEigenerMessageKeyFuerUebergang() {
      return true;
    }

    @Override
    public boolean isAusbleibend() {
      return true;
    }
  };

  private final UseCasePermission notwendigesRecht;

  Ergebniseingabestatus(UseCasePermission notwendigesRecht) {
    this.notwendigesRecht = notwendigesRecht;
  }

  public UseCasePermission getNotwendigesRecht() {
    return notwendigesRecht;
  }

  public boolean isVollstaendigerInternetExportMoeglich() {
    return FREIGEGEBEN.equals(this);
  }

  //ELECTDD-354
  public boolean isFreigegeben() {
    return FREIGEGEBEN.equals(this);
  }

  public boolean isEingabeMoeglich(Ergebniseingangsherkunft ergebniseingangsherkunft, BooleanSupplier eingangsherkunftIgnorieren) {
    return false;
  }

  public boolean isExportVonDokumentenMoeglich() {
    return ABGESCHLOSSEN.equals(this) || FREIGEGEBEN.equals(this);
  }

  private static final String MESSAGE_KEY_EINGABE_MOEGLICH_HERKUNFT_FALSCH = "stimmeingabe.erfassen.pruefen.eingabe.moeglich.herkunft.falsch";

  private static final String MESSAGE_KEY_EINGABE_ABGESCHLOSSEN = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.abgeschlossen";
  private static final String MESSAGE_KEY_EINGABE_ABGESCHLOSSEN_UNTERGEORDNET = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.abgeschlossen.untergeordnet";

  private static final String MESSAGE_KEY_EINGABE_FREIGEGEBEN = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.freigegeben";
  private static final String MESSAGE_KEY_EINGABE_FREIGEGEBEN_UNTERGEORDNET = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.freigegeben.untergeordnet";

  private static final String MESSAGE_KEY_EINGABE_GESPERRT = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.gesperrt";
  private static final String MESSAGE_KEY_EINGABE_GESPERRT_UNTERGEORDNET = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.gesperrt.untergeordnet";

  private static final String MESSAGE_KEY_EINGABE_AUSBLEIBEND = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.ausbleibend";

  private static final String MESSAGE_KEY_EINGABE_AUSBLEIBEND_UNTERGEORDNET = "stimmeingabe.erfassen.pruefen.eingabe.auf.gebiet.ausbleibend.untergeordnet";

  public abstract ElectCommonException getEingabeNichtMoeglichException(ErgebniseingangExceptionContext ergebniseingangExceptionContext);

  public abstract void addWarnMessageEingabeNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext);

  public abstract void addInfoMessageEingabeUntergeordnetNichtMoeglich(ErgebniseingangExceptionContext ergebniseingangExceptionContext);

  public boolean isFuerGebietZurAuswahl(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return wahldurchfuehrungsgebiet != null;
  }

  public boolean isGebietZaehltWeiterAlsErfassungsgebiet() {
    return true;
  }

  public static final List<Ergebniseingabestatus> STATUS_WEITER_ALS_ERFASSUNGSGEBIET = Arrays.stream(values())
          .filter(Ergebniseingabestatus::isGebietZaehltWeiterAlsErfassungsgebiet).collect(toList());

  public abstract String getIcon();

  public abstract Set<Ergebniseingabestatus> getFolgeStatus();

  public abstract boolean isEingabeBeendet();

  public boolean isEigenerMessageKeyFuerUebergang() {
    return false;
  }

  public boolean isAbgeschlossen() {
    return false;
  }

  public boolean isAusbleibend() {
    return false;
  }

  public boolean isGesperrt() {
    return false;
  }

  public boolean isEingabeMoeglichStatus() {
    return false;
  }

  public boolean isExternStatus() {
    return false;
  }

  public boolean isInternStatus() {
    return false;
  }

  protected static ElectCommonException getEingabeNichtMoeglichExceptionHerkunftFalsc(Ergebniseingabestatus aktuellerStatus, ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
    return new ElectCommonException(MESSAGE_KEY_EINGABE_MOEGLICH_HERKUNFT_FALSCH,
        ergebniseingangExceptionContext.getGebietDarstellung(), ergebniseingangExceptionContext.lokalisiereErgebniseingangsherkunft(), ergebniseingangExceptionContext.lokalisiere(aktuellerStatus));
  }

  protected static void addWarnMessageEingabeNichtMoeglichHerkunftFalsch(Ergebniseingabestatus aktuellerStatus, ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
    ergebniseingangExceptionContext.addWarnMessage(MESSAGE_KEY_EINGABE_MOEGLICH_HERKUNFT_FALSCH, ergebniseingangExceptionContext.getGebietDarstellung(), ergebniseingangExceptionContext.lokalisiereErgebniseingangsherkunft(), ergebniseingangExceptionContext.lokalisiere(aktuellerStatus));
  }

  protected static void addInfoMessageEingabeUntergeordnetNichtMoeglichHerkunftFalsc(Ergebniseingabestatus aktuellerStatus, ErgebniseingangExceptionContext ergebniseingangExceptionContext) {
    ergebniseingangExceptionContext.addInfoMessage(MESSAGE_KEY_EINGABE_MOEGLICH_HERKUNFT_FALSCH, ergebniseingangExceptionContext.getGebietDarstellung(), ergebniseingangExceptionContext.lokalisiereErgebniseingangsherkunft(), ergebniseingangExceptionContext.lokalisiere(aktuellerStatus));
  }
}
