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

import static de.ivu.elect.jee.entity.EntityUtil.castTo;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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

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

import de.ivu.elect.business.kandidatur.boundary.ListenkandidaturDAO;
import de.ivu.elect.business.kandidatur.boundary.ListenkandidaturEdit;
import de.ivu.elect.business.kandidatur.control.NlListenkandidaturSynchronisieren;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.person.entity.PersonStatus;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonenregisterAbgleichStatus;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonflikt;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktArt;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktStatus;
import de.ivu.elect.business.wahl.entity.Wahl;

@Stateless
@Specializes
public class NlPersonenKonfliktEdit extends PersonenKonfliktEdit {

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

  @Inject
  private transient ListenkandidaturDAO listenkandidaturDAO;

  @Inject
  private transient ListenkandidaturEdit listenkandidaturEdit;

  @Inject
  private transient NlListenkandidaturSynchronisieren nlListenkandidaturSynchronisieren;

  public NlPersonenKonfliktEdit() {
    super();
  }

  // ELECT-11211
  public void saveListenkandidaturZulassungAblehnenMitBemerkung(PersonenKonflikt personenKonflikt, KandidaturStatus kandidaturStatus, String kandidaturStatusBemerkung) {
    Collection<PersonenKonflikt> personenKonflikte = asList(personenKonflikt);

    saveAll(personenKonflikte);
    updatePersonendatenAndKonflikt(PersonStatus.GEEIGNET, PersonenKonfliktStatus.IRRELEVANT, personenKonflikte);

    Personendaten personendaten = getAttachedEntity(personenKonflikt).getPersonendaten();

    if (personendaten.isInstanceOf(Listenkandidatur.class)) {
      listenkandidaturEdit.setStatus(castTo(personendaten, Listenkandidatur.class), kandidaturStatus, kandidaturStatusBemerkung);
    }
  }

  public void deletePersonenKonfliktAndRestartPersonenPruefung(Wahl wahl) {
    long tic = System.currentTimeMillis();

    List<Personendaten> personendatenInWahl = new ArrayList<>(listenkandidaturDAO.findByWahl(wahl));
    LOG.info("Listenkandidaturen geladen [anzahl = {}, dauer = {} ms]", personendatenInWahl.size(), System.currentTimeMillis() - tic);

    tic = System.currentTimeMillis();

    List<PersonenKonflikt> personenKonflikteAbgleichFehlgeschlagen = dao.findByWahlAndKonfliktArtAndKonfliktStatus(wahl, singletonList(PersonenKonfliktArt.ABGLEICH_FEHLGESCHLAGEN),
        asList(PersonenKonfliktStatus.values()));
    LOG.info("Konflikte (Abgleich fehlgeschlagen) geladen [anzahl = {}, dauer = {} ms]", personenKonflikteAbgleichFehlgeschlagen.size(), System.currentTimeMillis() - tic);

    tic = System.currentTimeMillis();
    long personenKonflikteGeloeschtCount = 0;

    for (PersonenKonflikt personenKonflikt : personenKonflikteAbgleichFehlgeschlagen) {
      if (personendatenInWahl.contains(personenKonflikt.getPersonendaten())) {
        personenKonflikteGeloeschtCount++;

        dao.remove(personenKonflikt);
      }
    }

    LOG.info("Konflikte (Abgleich fehlgeschlagen) geloescht [anzahl = {}, dauer = {} ms]", personenKonflikteGeloeschtCount, System.currentTimeMillis() - tic);

    tic = System.currentTimeMillis();

    for (Personendaten person : personendatenInWahl) {
      person.setPersonStatus(PersonStatus.UNGEPRUEFT);
      person.setPersonenregisterAbgleichStatus(PersonenregisterAbgleichStatus.ABGLEICH_NOTWENDIG);
    }

    LOG.info("Listenkandidaturen aktualisiert [anzahl = {}, dauer = {} ms]", personendatenInWahl.size(), System.currentTimeMillis() - tic);

    startePersonenPruefung();
  }

  @Override
  public void updatePersonendatenAndKonflikt(PersonStatus personStatus, PersonenKonfliktStatus konfliktStatus, Collection<PersonenKonflikt> konflikte) {
    if (konflikte.size() == 1) {
      PersonenKonflikt konfliktBearbeitet = getAttachedEntity(konflikte.iterator().next());
      PersonenKonfliktArt personenKonfliktArt = konfliktBearbeitet.getPersonenKonfliktArt();

      if (PersonenKonfliktArt.ABGLEICH_FEHLGESCHLAGEN.equals(personenKonfliktArt)) {
        LOG.info("Konflikt (Abgleich fehlgeschlagen) aktualisieren {}", konfliktBearbeitet);

        Personendaten personendatenBearbeitet = konfliktBearbeitet.getPersonendaten();

        LOG.info("\t Synchronisiere verknuepfte Personendaten");

        nlListenkandidaturSynchronisieren.synchronisiereVerknuepftePersonen(personendatenBearbeitet, false /* Status nich geändert... */, false /* Position nicht verändert... */ ,
            false /* Personenprüfung wird am Ende eh gestartet... */ );

        for (Personendaten personendatenVerknuepft : personendatenBearbeitet.getIdentischVerknuepftePersonen()) {
          List<PersonenKonflikt> konflikteVerknuepft = dao.findByPersonAndKonfliktArt(personendatenVerknuepft, singletonList(personenKonfliktArt));

          for (PersonenKonflikt konfliktVerknuepft : konflikteVerknuepft) {
            LOG.info("\t Synchronisiere verknuepften Konflikt (Abgleich fehlgeschlagen)");

            konfliktBearbeitet.copyEntityAttributesUsingSetter(konfliktVerknuepft);

            updatePersonendatenAndKonfliktInternal(personStatus, konfliktStatus, konfliktVerknuepft);
          }
        }
      }
    }

    super.updatePersonendatenAndKonflikt(personStatus, konfliktStatus, konflikte);
  }
}
