
package de.ivu.elect.presentation.ergebniskonflikt;

import static java.util.Collections.singleton;
import static java.util.stream.Collectors.toSet;

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

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.ergebniskonflikt.entity.KandidaturenReihenfolgeErgebnisKonfliktCustomData;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.View;

@RequestScoped
@Named(ErgebnisKonfliktReihenfolgeKandidaturFestlegenEditView.COMPONENT_NAME)
@View(viewId = ErgebnisKonfliktReihenfolgeKandidaturFestlegenEditView.VIEW_ID, useCase = UseCasePermission.ERGEBNIS_KONFLIKT_EDIT)
public class ErgebnisKonfliktReihenfolgeKandidaturFestlegenEditView extends AbstractErgebnisKonfliktLoesenView<KandidaturenReihenfolgeErgebnisKonfliktCustomData> {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "ergebnisKonfliktReihenfolgeKandidaturFestlegenEditView";

  public static final String VIEW_ID = KandidaturenReihenfolgeErgebnisKonfliktCustomData.KONFLIKT_LOESUNG_VIEW_ID;

  private List<Kandidatur> kandidaturen;

  public ErgebnisKonfliktReihenfolgeKandidaturFestlegenEditView() {
    super();
  }

  @Override
  protected Collection<Gebiet> getErgebnisKonfliktGebiete() {
    return getKandidaturen().stream().filter(Kandidatur::hasGebiet).map(Kandidatur::getGebiet).filter(Objects::nonNull).collect(toSet());
  }

  @Override
  protected Class<KandidaturenReihenfolgeErgebnisKonfliktCustomData> getErgebnisKonfliktCustomDataClass() {
    return KandidaturenReihenfolgeErgebnisKonfliktCustomData.class;
  }

  public String formatKandidatur(Kandidatur kandidatur) {
    if (kandidatur == null) {
      return "";
    }

    return getErgebnisKonfliktCustomDataFormatter().collectDisplayNamePerKandidatur(singleton(kandidatur)).getOrDefault(kandidatur.getPk(), "");
  }

  public List<Kandidatur> getKandidaturen() {
    if (kandidaturen == null) {
      kandidaturen = ladeKandidaturen();
    }

    return kandidaturen;
  }

  @Override
  protected void addErgebnisKonfliktLoesungProperties(FormBuilder formBuilder, ErgebnisKonflikt ergebnisKonflikt) {
    // NOTE, dass die Liste zum Sortieren der Kandidaturen momentan in der XHTML-Seite definiert ist,
    // cf. /elect-was-war/src/main/webapp/ergebniskonflikt/ergebnis-konflikt-reihenfolge-kandidatur-festlegen-edit.xhtml.
  }

  private List<Kandidatur> ladeKandidaturen() {
    KandidaturenReihenfolgeErgebnisKonfliktCustomData customData = getCustomData(getEntity());

    /*
     * Achtung, an dieser Stelle nicht wundern, es besteht die fachliche Anforderung, dass die Kandidaturen anhand ihrer Position auf dem Stimmzettel angezeigt werden.
     *
     * TODO: Das naheliegendste(und einfachste), an dieser Stelle einen Comparator zu schreiben, der genau das sicherstellt, muss noch umgesetzt werden.
     *
     * Die Annahme ist bis jetzt, dass der Algorithmus zu Sitzberechnung die Kandidaturen in der richtigen Reihenfolge liefert. Der Algorithmus erhält die Kandidaturen und ihre Reihenfolge von der
     * Eingabe zum Algorithmus.
     *
     * Falls es jetzt also Probleme mit der Darstellung der korrekten Reihenfolge gibt, bestehen zwei Möglichkeiten:
     *
     * 1) Den Algorithmus verstehen, auf Probleme bei der Reihenfolge abklopfen, u.U. die Eingabe des Algorithmus verstehen und Probleme abklopfen
     *
     * ODER
     *
     * 2) sinnvoller Weise an dieser Stelle einen Comparator inkl. Testfall schreiben, der die benötigte Fachlichkeit abbildet
     */
    List<Kandidatur> kandidaturenUnsortiert = customData.getBeteiligteKandidaturen(kandidaturExtendedDAO);

    if (isErgebnisKonfliktGeloest()) {
      return customData.getGelosteKandidaturen(kandidaturenUnsortiert);
    }

    return kandidaturenUnsortiert;
  }

  public void setKandidaturen(List<Kandidatur> kandidaturen) {
    this.kandidaturen = kandidaturen;
  }

  @Override
  protected void updateErgebnisKonfliktLoesung(ErgebnisKonflikt ergebnisKonflikt) {
    // TODO NOTE, dass die sortierten Kandidaturen 'manuell' gesetzt werden müssen, da die UI-Komponente diese (noch)
    // nicht direkt setzt! Durch Verwendung eines Property im DynaForm-Model, cf. addErgebnisKonfliktLoesungProperties,
    // lässt sich dieser Aufwand umgehen und diese Methode kann entfernt werden.
    getCustomData(ergebnisKonflikt).setGelosteKandidaturen(getKandidaturen());

    super.updateErgebnisKonfliktLoesung(ergebnisKonflikt);
  }

  @Override
  protected String createErgebnisKonfliktLoesungBeschreibung(KandidaturenReihenfolgeErgebnisKonfliktCustomData ergebnisKonfliktCustomData) {
    return ergebnisKonfliktCustomData.createLoesungBeschreibung(getErgebnisKonfliktCustomDataFormatter(), kandidaturExtendedDAO, ergebnisKonfliktCustomData.getGelosteKandidaturenPKs());
  }

  @Redirect
  @Override
  public String reset() {
    kandidaturen = null;

    return super.reset();
  }
}
