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

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.datei.entity.DateiImportBerichtCustomData;
import de.ivu.elect.business.ergebnis.control.GewaehltCreate;
import de.ivu.elect.business.ergebnis.control.GewaehlteImportContext;
import de.ivu.elect.business.ergebnis.control.GewaehlteImportExchange;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.GewaehltMeta;
import de.ivu.elect.business.exchange.control.AbstractEntityImporter;
import de.ivu.elect.business.exchange.control.ImportExchange;
import de.ivu.elect.business.kandidatur.boundary.KandidaturDAO;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturExtendedTK;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.jee.entity.Meta;
import de.ivu.elect.jee.exchange.ImportOptions;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;

@Stateless
public class GewaehlteImporter
    extends
      AbstractEntityImporter<Gewaehlt, KandidaturExtendedTK, GewaehlteImportContext, DateiImportBerichtCustomData> {

  @Inject
  private transient ErgebnisImportSearch ergebnisImportSearch;

  @Inject
  private transient GewaehlteImportExchange gewaehlteImportExchange;

  @Inject
  private transient GewaehltMeta gewaehltMeta;

  @Inject
  private transient GewaehltDAO gewaehltDAO;

  @Inject
  private transient GewaehltCreate gewaehltCreate;

  @Inject
  private transient KandidaturDAO kandidaturDAO;

  @Inject
  private transient GebietNummerFormatter gebietNummerFormatter;

  @Override
  protected void persistiere(Collection<Gewaehlt> neueEntities, GewaehlteImportContext context,
      DateiImportBerichtCustomData customDateiImportBerichtCustomData, StringBuilder bericht) {
    Ergebnis ergebnis = findeErgebnis(context);

    Map<KandidaturExtendedTK, Kandidatur> kandidaturenInDB = Kandidatur.mappeKandidaturenNachExtendedTK(kandidaturDAO
        .findByWahl(ergebnis.getWahl())/*ELECTKOM-117*/.stream().filter(k->k.getWahlvorschlag()!=null).collect(Collectors.toList()));

    for (Gewaehlt gewaehlt : neueEntities) {
      gewaehlt.setErgebnis(ergebnis);
      gewaehlt.setKandidatur(kandidaturenInDB.get(gewaehlt.getKandidatur().getKandidaturExtendedTK()));
      gewaehltCreate.save(gewaehlt);
    }
  }

  @Override
  protected void aktualisiere(Gewaehlt entityInDatei, Gewaehlt entityInDatenbank, GewaehlteImportContext context,
      DateiImportBerichtCustomData customDateiImportBerichtCustomData, StringBuilder bericht) {
    entityInDatenbank.setGewaehltStatus(entityInDatei.getGewaehltStatus());
    entityInDatenbank.setGewaehltStatusVergabe(entityInDatei.getGewaehltStatusVergabe()); // ELECT-16036
  }

  @Override
  protected void loescheAusDatenbank(Collection<Gewaehlt> entitiesInDb, GewaehlteImportContext context,
      DateiImportBerichtCustomData customDateiImportBerichtCustomData, StringBuilder bericht) {
    for (Gewaehlt gewaehlt : entitiesInDb) {
      gewaehltDAO.remove(gewaehlt);
    }
  }

  @Override
  protected List<Gewaehlt> getAllEntitiesInDB(GewaehlteImportContext context) {
    Ergebnis ergebnis = findeErgebnis(context);
    return gewaehltDAO.findByErgebnis(ergebnis);
  }

  private Ergebnis findeErgebnis(GewaehlteImportContext context) {
    return ergebnisImportSearch.loadUniqueErgebnis(context.getWahl(), context.getZiel());
  }

  private static final Function<Gewaehlt, KandidaturExtendedTK> TO_TK = new Function<Gewaehlt, KandidaturExtendedTK>() {

    @Override
    public KandidaturExtendedTK apply(Gewaehlt value) {
      return new KandidaturExtendedTK(value.getKandidatur());
    }
  };

  @Override
  protected Function<Gewaehlt, KandidaturExtendedTK> getEntityToEntityTKFunction() {
    return TO_TK;
  }

  @Override
  protected void validiere(Violations violations, List<Gewaehlt> importObject, GewaehlteImportContext context, ImportOptions importOptions) {
    Ergebnis ergebnis = findeErgebnis(context);

    Map<KandidaturExtendedTK, Kandidatur> kandidaturenInDB = Kandidatur.mappeKandidaturenNachExtendedTK(kandidaturDAO
        .findByWahl(ergebnis.getWahl())/*ELECTKOM-117*/.stream().filter(k->k.getWahlvorschlag()!=null).collect(Collectors.toList()));

    for (Gewaehlt gewaehlt : importObject) {
      Kandidatur kandidatur = gewaehlt.getKandidatur();
      KandidaturExtendedTK kandidaturExtendedTK = kandidatur.getKandidaturExtendedTK();
      if (!kandidaturenInDB.containsKey(kandidaturExtendedTK)) {
        String gebietsnameMitNummer = gebietNummerFormatter.getNameMitNummer(kandidatur.getGebiet());
        String gruppenname = kandidatur.getGruppe().getName();
        final String listenposition;
        if (kandidatur.isListenkandidatur()) {
          listenposition = String.valueOf(kandidatur.castTo(Listenkandidatur.class).getEntity().getRelativePosition());
        } else {
          listenposition = "--";
        }

        violations.addError("gewaehlte.import.kandidatur.fehlt", kandidatur.getNamePraesentation(),
            gebietsnameMitNummer, gruppenname, listenposition);
      }
    }
  }

  @Override
  protected void erstelleBericht(List<Gewaehlt> importObject, GewaehlteImportContext context,
      ImportOptions importOptions, StringBuilder bericht, boolean vorab) {
    List<Gewaehlt> allEntitiesInDB = getAllEntitiesInDB(context);
    int anzahlInDB = getAnzahlGewaehlte(allEntitiesInDB);
    int anzahlInDatei = getAnzahlGewaehlte(importObject);

    if (anzahlInDB > 0) {
      bericht.append(getMessage("gewaehlte.import.bericht.hinweis.ueberschrieben"));
      bericht.append("\n");
      bericht.append(getMessage("gewaehlte.import.bericht.anzahl.in.datenbank", anzahlInDB));
      bericht.append("\n");
    } else {
      bericht.append(getMessage("gewaehlte.import.bericht.hinweis.keine.vorhanden"));
      bericht.append("\n");
    }
    bericht.append(getMessage("gewaehlte.import.bericht.anzahl.in.datei", anzahlInDatei));
    bericht.append("\n");

    if (!vorab) {
      bericht.append("\n");
      bericht.append(getMessage("gewaehlte.import.bericht.hinweis.alle.gefunden"));
    }
  }

  private int getAnzahlGewaehlte(List<Gewaehlt> gewaehlte) {
    return (int) gewaehlte.stream().filter(gewaehlter -> Boolean.TRUE.equals(gewaehlter.getIstGewaehlt())).count();
  }

  @Override
  protected ImportExchange<List<Gewaehlt>, GewaehlteImportContext> getExchange() {
    return gewaehlteImportExchange;
  }

  @Override
  public Meta getMetaForEntityInternal() {
    return gewaehltMeta;
  }

}
