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

import java.util.Collection;
import de.ivu.elect.business.kandidatur.boundary.AbstractListenkandidaturDAO;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractListeDAO;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.StelInformationen;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.wahlvorschlag.boundary.AbstractListeDAO;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.StelInformationen;

public enum NlPruefkriteriumAuswirkung {

  LISTE {
    @Override
    public boolean isListe() {
      return true;
    }

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

    @Override
    public List<Liste> bestimmeListen(Liste liste, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      return Collections.singletonList(liste);
    }
    @Override
    public List<Wahlrechtspruefung> bestimmeKandidaturen(Collection<Wahlrechtspruefung> kandidaturen , Wahlrechtspruefung kandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      return kandidaturen.stream().filter(k->k.getGebiet().equals(kandidatur.getGebiet())).collect(Collectors.toList());
    }

    @Override
    public List<Listenkandidatur> bestimmeListenkandidaturen(Listenkandidatur listenkandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      return Collections.singletonList(listenkandidatur);
    }

  }, // Nur auf einzelne Liste im Wahlkreis
  STEL {
    @Override
    public boolean isListe() {
      return false;
    }

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

    @Override
    public List<Liste> bestimmeListen(Liste liste, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      return stelInformationenSupplier.get().getListenDesStels().stream().map(listeDAO::findByPrimaryKey).collect(Collectors.toList());
    }
    @Override
    public List<Wahlrechtspruefung> bestimmeKandidaturen(Collection<Wahlrechtspruefung> kandidaturen ,Wahlrechtspruefung kandidatur, Supplier<StelInformationen> stelInformationenSupplier,  AbstractListeDAO listeDAO) {

      List<Liste> stelLists = stelInformationenSupplier.get().getListenDesStels().stream().map(listeDAO::findByPrimaryKey).collect(Collectors.toList());
      return kandidaturen.stream().filter(l -> stelLists.contains(l.getKandidatur().castTo(Listenkandidatur.class).getEntity().getListe())).collect(Collectors.toList());
    }
    @Override
    public List<Listenkandidatur> bestimmeListenkandidaturen(Listenkandidatur listenkandidatur, Supplier<StelInformationen> stelInformationenSupplier,  AbstractListeDAO listeDAO) {
      Collection<Listenkandidatur> identischVerknuepfteListenkandidaturen = listenkandidatur.getIdentischVerknuepfteListenkandidaturen();
      identischVerknuepfteListenkandidaturen.add(listenkandidatur);
      List<Liste> stelLists = stelInformationenSupplier.get().getListenDesStels().stream().map(listeDAO::findByPrimaryKey).collect(Collectors.toList());
      return identischVerknuepfteListenkandidaturen.stream().filter(listenkandidatur1 -> stelLists.contains(listenkandidatur1.getListe())).collect(Collectors.toList());
    }
  }, // Nur auf alle Listen desselben Stels
  GRUPPE {
    @Override
    public boolean isListe() {
      return false;
    }

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

    @Override
    public List<Liste> bestimmeListen(Liste liste, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      return listeDAO.findByGruppe(liste.getGruppe());
    }
    @Override
    public List<Wahlrechtspruefung> bestimmeKandidaturen(Collection<Wahlrechtspruefung> kandidaturen , Wahlrechtspruefung kandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {

      return kandidaturen.stream().filter(w -> kandidatur.getKandidatur().getGruppe().equals(w.getKandidatur().getGruppe())).collect(Collectors.toList());
    }

    @Override
    public List<Listenkandidatur> bestimmeListenkandidaturen(Listenkandidatur listenkandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO) {
      Collection<Listenkandidatur> identischVerknuepfteListenkandidaturen = listenkandidatur.getIdentischVerknuepfteListenkandidaturen();
      identischVerknuepfteListenkandidaturen.add(listenkandidatur);
      return identischVerknuepfteListenkandidaturen.stream().filter(listenkandidatur1 -> listenkandidatur.getGruppe().equals(listenkandidatur1.getGruppe())).collect(Collectors.toList());
    }
  }; // Auf alle Listen derselben Gruppe

  public abstract boolean isListe();
  public abstract boolean isGruppe();

  public abstract List<Liste> bestimmeListen(Liste liste, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO);
  public abstract List<Wahlrechtspruefung> bestimmeKandidaturen(Collection<Wahlrechtspruefung> kandidaturen , Wahlrechtspruefung kandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO);
  public abstract List<Listenkandidatur> bestimmeListenkandidaturen(Listenkandidatur listenkandidatur, Supplier<StelInformationen> stelInformationenSupplier, AbstractListeDAO listeDAO);

  public static NlPruefkriteriumAuswirkung from(Pruefkriterium pruefkriterium) {
    return from(pruefkriterium.getUnterkategorie());
  }

  public static NlPruefkriteriumAuswirkung from(String text) {
    if (StringUtils.isBlank(text)) {
      return NlPruefkriteriumAuswirkung.DEFAULT;
    }
    return valueOf(text);
  }

  public static final String AUSWIRKUNG_CONTEXT_KEY = "AUSWIRKUNG_CONTEXT_KEY";
  public static final String ALTER_WAHLRECHTSPRUEF_STATUS_KEY = "ALTER_WAHLRECHTSPRUEF_STATUS_KEY";
  public static final String BEMERKUNG_AFTER_ACTION_KEY = "BEMERKUNG_AFTER_ACTION_KEY";

  public static final NlPruefkriteriumAuswirkung DEFAULT = NlPruefkriteriumAuswirkung.STEL; // sinnvolles Default bis zur genauen Definition

}
