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

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.inject.Inject;

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

import de.ivu.elect.business.ElectSystemProperties;
import de.ivu.elect.business.datei.entity.DateiImportBerichtCustomData;
import de.ivu.elect.business.dokumente.boundary.DokumentVorlageDAO;
import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisDAO;
import de.ivu.elect.business.ergebnis.control.StimmergebnisDaten;
import de.ivu.elect.business.ergebnis.control.StimmergebnisDatenCreator;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.mandant.boundary.MandantDAO;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.mandant.entity.MandantPK;
import de.ivu.elect.business.wahl.boundary.WahlDAO;
import de.ivu.elect.business.wahl.boundary.WahlEdit;
import de.ivu.elect.business.wahl.boundary.WahldurchfuehrungDAO;
import de.ivu.elect.business.wahl.boundary.WasWahlImporter;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlImportContext;
import de.ivu.elect.business.wahl.entity.WahlPK;
import de.ivu.elect.business.wahl.entity.WahlaufteilenResultContainer;
import de.ivu.elect.business.wahl.entity.WahlaufteilenStatusContainer;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.jee.exchange.ImportOptions;


import static java.util.Collections.emptyList;

@Stateless
public class WahlMandantenAufteilenSynchron {

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

  private static final long ANZAHL_MANDANTEN_PRO_TRANSAKTION = 10L;

  @Inject
  private transient WahldurchfuehrungDAO wahldurchfuehrungDAO;

  @Inject
  private transient StimmergebnisDatenCreator stimmergebnisDatenCreator;

  @Inject
  private transient DokumentVorlageDAO dokumentVorlageDAO;

  @Inject
  private transient MandantDAO mandantDAO;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient WahlAufteiler wahlAufteiler;

  @Inject
  private transient WahlAufteilerExportImportMapper wahlAufteilerExportImportMapper;

  @Inject
  private transient WasWahlImporter wasWahlImporter;

  @Inject
  private transient ErgebnisDAO ergebnisDAO;

  @Inject
  private transient WahlDAO wahlDAO;

  @Inject
  private transient WahlEdit wahlEdit;

  @Inject
  private transient WahlMandantenAufteilenStatusErmittler wahlMandantenAufteilenStatusErmittler;

  public Map<MandantPK, WahlaufteilenResultContainer> aufteilen(WahlPK wahlPK, Collection<MandantPK> mandantPKS) {

    LOG.info("Aufteilen: " + mandantPKS + ", wahlPK=" + wahlPK);
    Wahldurchfuehrung wahl = wahldurchfuehrungDAO.findByPrimaryKey(wahlPK);

    Map<MandantPK, WahlaufteilenResultContainer> result = new HashMap<>();

    for (MandantPK mandantPK : mandantPKS) {
      WahlaufteilenStatusContainer wahlaufteilenStatusContainer = wahlMandantenAufteilenStatusErmittler.bestimmeStatusFuerMandant(wahlPK, mandantPK);
      if (wahlaufteilenStatusContainer.getWahlaufteilenStatus().isAufteilenMoeglich()) {
        Mandant mandant = mandantDAO.findByPrimaryKey(mandantPK);

        StimmergebnisDaten stimmergebnisDaten = stimmergebnisDatenCreator.createErgebnisDatenExporte(wahl.bestimmeZuBerechnendesErgebnis(ergebnisDAO));
        List<DokumentVorlage> dokumentvorlagen = dokumentVorlageDAO.findByWahlOrderByArtAndName(wahl);

        // ELECTKOM-446 List<WahlParameter> wahlParameters = wahlParameterDAO.findByWahl(wahl);

        LOG.info("Aufteilen für Mandant: " + mandant);
        Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = wahldurchfuehrungsgebietDAO
            .findByPrimaryKey(wahlaufteilenStatusContainer.getWurzelgebiete().get(0));
        // Neues Wurzelgebiet
        StimmergebnisDaten stimmergebnisDatenFuerMandant = wahlAufteiler
            .erzeugeStimmergebnisMappedFuerAufgeteiltesGebiet(stimmergebnisDaten, wahldurchfuehrungsgebiet);
        // Objekte von der Datenbank lösen
        WahlImportObject wahlImportObject = wahlAufteilerExportImportMapper
            .copyTo(new WahlExportObject(stimmergebnisDatenFuerMandant, dokumentvorlagen, emptyList()/*ELECTKOM-446*/));
        // Importieren
        WahlImportContext wahlImportContext = new WahlImportContext(mandant);
        DateiImportBerichtCustomData customDateiImportBericht = new DateiImportBerichtCustomData();
        wasWahlImporter
            .importieren(wahlImportObject, ImportOptions.NEUE_DATEN_ANLEGEN_BESTEHENDE_DATEN_UNVERAENDERT_LASSEN, customDateiImportBericht, wahlImportContext);
        Wahldurchfuehrung wahlFuerMandant = wahldurchfuehrungDAO.findByPrimaryKey(wahlImportContext.getWahlPK());
        wahlFuerMandant.setBerichtetAn(wahl);
        result.put(mandantPK, new WahlaufteilenResultContainer(true, customDateiImportBericht));

        LOG.info("Aufteilen für Mandant: " + mandant + " - done");
      } else {
        result.put(mandantPK, new WahlaufteilenResultContainer(false, new DateiImportBerichtCustomData()));
      }
    }
    LOG.info("Aufteilen: " + mandantPKS + ", wahlPK=" + wahlPK + " - done");
    return result;
  }

  public long bestimmeAnzahlMandantenProTransaktion() {
    try {
      long l = Long.parseLong(System.getProperty(ElectSystemProperties.ELECT_WAHL_AUFTEILEN_MANDANTEN_PRO_TRANSAKTION));
      if (l > 0) {
        return l;
      }
    } catch (Exception e) {
      LOG.warn("Fehler beim Bestimmen der Anzahl der Mandanten pro Transaktion: " + e.getMessage());
    }
    return ANZAHL_MANDANTEN_PRO_TRANSAKTION;
  }

  public void loeschen(WahlPK wahlPK, Collection<MandantPK> mandantPKS) {
    LOG.info("Löschen: " + mandantPKS + ", wahlPK=" + wahlPK);
    Wahldurchfuehrung wahl = wahldurchfuehrungDAO.findByPrimaryKey(wahlPK);
    for (MandantPK mandantPK : mandantPKS) {
      Mandant mandant = mandantDAO.findByPrimaryKey(mandantPK);
      for (Wahl wahlZuloeschen : wahlDAO.findByBerichtetAnAndMandant(wahl, mandant)) {
        LOG.info("Lösche Wahl: " + wahlZuloeschen);
        wahlEdit.delete(wahlZuloeschen);
      }
    }
    LOG.info("Löschen: " + mandantPKS + ", wahlPK=" + wahlPK + " - done");
  }
}
