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

import de.ivu.elect.business.gebietsbaum.boundary.AbstractGebietDAO;
import de.ivu.elect.business.gebietsbaum.control.EntityMitWurzelgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.EntityMitGebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatterKandidaturFormatDarstellung;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahltermin;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Predicate;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

public class ErgebnisExchangeContext {

  public static final StimmzettelFormatterKandidaturFormatDarstellung KANDIDATUR_FORMAT_DARSTELLUNG_NOT_CONFIGURED = null; // == Fallback auf default...

  private final Wahl wahl;

  private final Collection<GebietPK> auswertungsgebietePKs;

  private final boolean auswertungsgebieteIgnored;

  private final StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung;

  public ErgebnisExchangeContext(Wahl wahl, Gebiet auswertungsgebiet, StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung) {
    this(wahl, auswertungsgebiet == null ? emptyList() : asList(auswertungsgebiet), kandidaturFormatDarstellung);
  }

  public ErgebnisExchangeContext(Wahl wahl, Collection<Gebiet> auswertungsgebiete, StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung) {
    super();

    this.wahl = wahl;

    Collection<Gebiet> auswertungsgebieteRelevant = auswertungsgebiete.stream().filter(Objects::nonNull).filter(Gebiet::isPersistent).collect(toSet());

    this.auswertungsgebietePKs = auswertungsgebieteRelevant.stream().map(Gebiet::getPk).collect(toList());
    this.auswertungsgebieteIgnored = auswertungsgebieteRelevant.isEmpty() || auswertungsgebieteRelevant.stream().anyMatch(Gebiet::isWurzelgebiet);

    this.kandidaturFormatDarstellung = kandidaturFormatDarstellung;
  }

  public Wahl getWahl() {
    return wahl;
  }

  public Gebiet getWurzelgebiet(AbstractGebietDAO gebietDAO) {
    return getWahl().getWurzelgebiet(EntityMitWurzelgebietDAO.fromDao(gebietDAO));
  }

  public Collection<Gebiet> getAuswertungsgebiete(AbstractGebietDAO gebietDAO) {
    return auswertungsgebietePKs.stream().map(gebietDAO::findByPrimaryKey).collect(toSet());
  }

  public <T extends EntityMitGebiet> Collection<T> collectEntitiesExportierbar(AbstractGebietDAO gebietDAO, Collection<T> entities) {
    return entities.stream().filter(entityExportierbar(gebietDAO, getAuswertungsgebiete(gebietDAO))).collect(toSet());
  }

  // ELECT-9497
  private <T extends EntityMitGebiet> Predicate<T> entityExportierbar(AbstractGebietDAO gebietDAO, Collection<Gebiet> auswertungsgebiete) {
    return entityMitGebiet -> {
      if (entityMitGebiet != null) {
        Gebiet gebiet = gebietDAO.attach(entityMitGebiet.getGebiet());

        return gebiet != null && (auswertungsgebieteIgnored || auswertungsgebiete.stream().anyMatch(gebiet::isInGebietshierarchieVon));
      }

      return false;
    };
  }

  @Nullable
  public StimmzettelFormatterKandidaturFormatDarstellung getKandidaturFormatDarstellung() {
    return kandidaturFormatDarstellung;
  }

  @Nullable
  public Wahltermin getWahltermin() {
    if (getWahl() == null) {
      return null;
    }
    return getWahl().getWahltermin();
  }
}
