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

import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;

import java.util.Collection;
import java.util.Comparator;
import java.util.EnumSet;

import de.ivu.elect.business.wahl.entity.NlWahlCustomData;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.Messages;

// ELECT-15447
public enum NlGebietsgruppierungArt {

  /**
   * "Das Wahllokal hat in der amtlichen Meldung eines oder mehrerer Wahllokale eine Differenz zwischen der Zahl der zugelassenen Wähler und der Zahl der ausgezählten Stimmzettel festgestellt, für die
   * das Wahllokal keine Erklärung geliefert hat."
   */
  ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_STIMMZETTEL_EINGENOMMEN_ABWEICHEND {

    @Override
    protected boolean isAccept(Wahl wahl) {
      return true; // ELECT-15734, ELECT-16526
    }

    @Override
    public NlGebietKorrekturenStimmeingabenStatus getKorrekturenStimmeingabenStatus() {
      return NlGebietKorrekturenStimmeingabenStatus.PRUEFUNG_ERFORDERLICH;
    }
  },

  /**
   * ELECT-16526, "Stimmbezirke, bei denen der Verdacht besteht, dass die Niederschrift Fehler enthält"
   */
  ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_FEHLER_IN_NIEDERSCHRIFT_VERMUTET {

    @Override
    protected boolean isAccept(Wahl wahl) {
      return NlWahlart.isNurBriefwahlAuslandUnterstuetzt(wahl); // ELECT-15734
    }

    @Override
    public NlGebietKorrekturenStimmeingabenStatus getKorrekturenStimmeingabenStatus() {
      return NlGebietKorrekturenStimmeingabenStatus.PRUEFUNG_ERFORDERLICH;
    }
  },

  /**
   * "Soweit die erneute Stimmenauszählung zu einer Berichtigung einer oder mehrerer vom Wahllokal (mit Differenz zwischen der Zahl der zugelassenen Wähler und der Zahl der ausgezählten Stimmzettel)
   * ermittelter Zahlen geführt hat, hat das Wahlamt die korrigierten Zahlen in einer Berichtigung festgehalten."
   */
  ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT_STIMMZETTEL_EINGENOMMEN_ABWEICHEND {

    @Override
    protected boolean isAccept(Wahl wahl) {
      return NlWahlart.isUrnenwahlUnterstuetzt(wahl) && !wahl.getCustomData(NlWahlCustomData.class).isZentraleErfassung(); // ELECT-15734
    }

    @Override
    public NlGebietKorrekturenStimmeingabenStatus getKorrekturenStimmeingabenStatus() {
      return NlGebietKorrekturenStimmeingabenStatus.NACH_PRUEFUNG_KORRIGERT;
    }
  },

  /**
   * "Das Wahllokal hat einen oder mehrere (andere) Fehler im amtlichen Bericht eines oder mehrerer Wahllokale festgestellt und diese Fehler für jedes dieser Wahllokale in einer Berichtigung
   * korrigiert."
   */
  ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT {

    @Override
    protected boolean isAccept(Wahl wahl) {
      return NlWahlart.isUrnenwahlUnterstuetzt(wahl) && !wahl.getCustomData(NlWahlCustomData.class).isZentraleErfassung(); // ELECT-15734
    }

    @Override
    public NlGebietKorrekturenStimmeingabenStatus getKorrekturenStimmeingabenStatus() {
      return NlGebietKorrekturenStimmeingabenStatus.NACH_PRUEFUNG_KORRIGERT;
    }
  },

  ;

  public static final Collection<NlGebietsgruppierungArt> ARTEN_KORREKTUREN_ERFASSUNGSGEBIETE = EnumSet.of( //
      NlGebietsgruppierungArt.ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_FEHLER_IN_NIEDERSCHRIFT_VERMUTET, //
      NlGebietsgruppierungArt.ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_STIMMZETTEL_EINGENOMMEN_ABWEICHEND, //
      NlGebietsgruppierungArt.ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT_STIMMZETTEL_EINGENOMMEN_ABWEICHEND, //
      NlGebietsgruppierungArt.ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT //
  );

  NlGebietsgruppierungArt() {
  }

  public String getArt() {
    return name();
  }

  protected abstract boolean isAccept(Wahl wahl);

  public boolean isPruefungNichtErforderlich() {
    return getKorrekturenStimmeingabenStatus().isPruefungNichtErforderlich();
  }

  public boolean isPruefungErforderlich() {
    return getKorrekturenStimmeingabenStatus().isPruefungErforderlich();
  }

  public boolean isPruefungErfolgt() {
    return getKorrekturenStimmeingabenStatus().isPruefungErfolgt();
  }

  public String getIconGebietsbaum(Messages messages) {
    return getKorrekturenStimmeingabenStatus().getIconGebietsbaum(messages);
  }

  public abstract NlGebietKorrekturenStimmeingabenStatus getKorrekturenStimmeingabenStatus();

  public static Collection<NlGebietsgruppierungArt> collectArtenKorrekturenErfassungsgebiete(Wahl wahl) {
    if (wahl == null) {
      return emptyList();
    }

    return ARTEN_KORREKTUREN_ERFASSUNGSGEBIETE.stream() //
        .filter(value -> value.isAccept(wahl)).sorted(Comparator.comparing(Enum::ordinal)) //
        .collect(toList());
  }

  public static String getMsgKeyHeader(Wahl wahl, Gebietsgruppierung gebietsgruppierung) {
    return getMsgKeyPrefix(wahl, gebietsgruppierung) + ".header";
  }

  public static String getMsgKeyLabel(Wahl wahl, Gebietsgruppierung gebietsgruppierung) {
    return getMsgKeyPrefix(wahl, gebietsgruppierung) + ".label";
  }

  private static String getMsgKeyPrefix(Wahl wahl, Gebietsgruppierung gebietsgruppierung) {
    String result = "NlGebietsgruppierungArt." + gebietsgruppierung.getGebietsgruppierungArt();

    if (wahl != null && wahl.getCustomData(NlWahlCustomData.class).isZentraleErfassung()) {
      result += ".zentral";
    }

    return result;
  }
}
