
package de.ivu.elect.business.wahl.boundary;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.enterprise.inject.Specializes;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.CurrentCustomer;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsarteigenschaft;
import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.wahl.control.Wahldaten;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlImportContext;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.presentation.NlElectionLevel;
import de.ivu.elect.presentation.NlSystemProperties;

@Specializes
public class NlWasWahlImportHelper extends NlWahlImportHelper {

  private static final long serialVersionUID = 1L;

  private static final Logger LOG = LoggerFactory.getLogger(NlWasWahlImportHelper.class);

  public static final String CONTEXT_PARAM_ALS_WAHLDEFINITION_IMPORTIEREN = "CONTEXT_PARAM_ALS_WAHLDEFINITION_IMPORTIEREN";

  public static final String CONTEXT_PARAM_WURZELGEBIET = "CONTEXT_PARAM_WURZELGEBIET";

  @Inject
  private transient WahlartDAO wahlartDAO;

  @Inject
  private transient CurrentCustomer currentCustomer;

  @Inject
  private transient NlSystemProperties nlSystemProperties;

  public NlWasWahlImportHelper() {
    super();
  }

  @Override
  public Wahlart findeWahlartInDb(Wahlart wahlart, WahlImportContext context) {
    if (Customer.NL_WAS.equals(currentCustomer.getCustomer())) {
      NlWahlart nlWahlart = NlWahlart.valueOf(wahlart);

      List<Wahlart> alleWahlartKandidaten = wahlartDAO.findByAllOrderByName(context.getMandant()).stream().filter(nlWahlart::equalsWahlart)
          .collect(Collectors.toList());

      LOG.info("alleWahlartKandidaten: " + alleWahlartKandidaten);

      NlElectionLevel defaultElectionLevel = nlSystemProperties.getDefaultElectionLevel(context.getMandant());
      LOG.info("defaultElectionLevel: " + defaultElectionLevel);

      return alleWahlartKandidaten.stream().filter(wahlartResult -> NlWahlart.matches(wahlartResult, defaultElectionLevel, currentCustomer.getCustomer()))
          .findFirst().orElseThrow(() -> new IllegalArgumentException("Wahlart nicht gefunden: " + wahlart));
    } else {
      throw new RuntimeException("TODO FIXME NUR FÜR NL-WAS");
    }

  }

  @Override
  public void postCreateGebiete(List<Gebiet> gebiete) {
    // Sitze werden im EML Mapper* am obersten Gebiet gespeichert, nach dem Import an die Wahlgebiete hängen
    // *) de.ivu.elect.was.exchange.wahl.Eml110Mapper.mappeGebiete
    Long anzahlSitze = gebiete.stream().filter(g -> !g.hasUebergeordnetesGebiet()).map(Gebiet::getAnzahlSitze).findAny().orElse(null);

    if (anzahlSitze != null) {
      for (Gebiet gebiet : gebiete) {
        if (gebiet.isWahlgebiet()) {
          gebiet.setAnzahlSitze(anzahlSitze);
        } else {
          gebiet.setAnzahlSitze(null);
        }
      }
    }
  }

  @Override
  public List<Gebiet> filterZuImportierendeGebiete(Wahldaten<Wahl, Gebiet> wahldaten, Wahlart wahlartInDb) {
    if (wahlartInDb == null) {
      return Collections.emptyList();
    }

    Set<String> bekannteGebietsarten = wahlartInDb.getGebietsarteigenschaften().stream().map(Gebietsarteigenschaft::getGebietsart).map(Gebietsart::getName).collect(Collectors.toSet());

    List<Gebiet> alleGebiete = wahldaten.getGebiete();
    Set<Gebiet> gebieteOhneVorhandenerGebietsartOderDarunter = alleGebiete.stream().filter(gebiet -> !bekannteGebietsarten.contains(gebiet.getGebietsart().getName())).collect(Collectors.toSet());

    boolean changed;

    do {
      changed = false;
      for (Gebiet gebiet : alleGebiete) {
        if (gebiet.getUebergeordnetesGebiet() != null && gebieteOhneVorhandenerGebietsartOderDarunter.contains(gebiet.getUebergeordnetesGebiet())) {
          changed |= gebieteOhneVorhandenerGebietsartOderDarunter.add(gebiet);
        }
      }

    } while (changed);

    return alleGebiete.stream().filter(gebiet -> !gebieteOhneVorhandenerGebietsartOderDarunter.contains(gebiet)).collect(Collectors.toCollection(() -> new ArrayList<>(alleGebiete.size())));
  }
}
