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

import static de.ivu.elect.jee.entity.EntityUtil.castTo;

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

import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.kandidatur.entity.*;
import de.ivu.elect.business.person.entity.PersonStatus;
import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.personenpruefung.boundary.PersonenPruefungStarter;
import de.ivu.elect.business.wahlrechtspruefung.boundary.WahlrechtspruefungDAO;
import de.ivu.elect.business.wahlrechtspruefung.entity.Wahlrechtspruefung;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStatus;

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

@Stateless
public class ErsatzkandidaturAufruecken {

  @Inject
  protected transient KandidaturDAO kandidaturDao;

  @Inject
  protected transient ErsatzkandidaturDAO ersatzkandidaturDao;

  @Inject
  protected transient DirektkandidaturDAO direktkandidaturDao;

  @Inject
  protected transient DirektkandidaturFactory direktkandidaturFactory;

  @Inject
  protected transient ListenkandidaturDAO listenkandidaturDao;

  @Inject
  protected transient ListenkandidaturFactory listenkandidaturFactory;

  @Inject
  protected transient WahlrechtspruefungDAO wahlrechtspruefungDAO;

  @Inject
  protected PersonenPruefungStarter personenPruefungStarter;

  public ErsatzkandidaturAufruecken() {
    super();
  }

  public void aufruecken(Ersatzkandidatur entity) {
    Ersatzkandidatur ersatzkandidatur = attach(entity);

    Kandidatur kandidatur = null;
    boolean kandidaturGeeignetOderNichtZuPruefen = ersatzkandidatur.isPersonStatusGeeignetOderNichtZuPruefen();

    Kandidatur uebergeordneteKandidaturToReplace = ersatzkandidatur.getUebergeordneteKandidatur();

    if (uebergeordneteKandidaturToReplace.isInstanceOf(Listenkandidatur.class)) {
      kandidatur = aufruecken(ersatzkandidatur, castTo(uebergeordneteKandidaturToReplace, Listenkandidatur.class));
    } else if (uebergeordneteKandidaturToReplace.isInstanceOf(Direktkandidatur.class)) {
      kandidatur = aufruecken(ersatzkandidatur, castTo(uebergeordneteKandidaturToReplace, Direktkandidatur.class));
    } else if (uebergeordneteKandidaturToReplace.isInstanceOf(Ersatzkandidatur.class)) {
      kandidatur = aufruecken(ersatzkandidatur, castTo(uebergeordneteKandidaturToReplace, Ersatzkandidatur.class));
    }

    if (kandidatur != null && !kandidaturGeeignetOderNichtZuPruefen) { // ELECT-8987
      kandidatur.setPersonStatus(PersonStatus.UNGEPRUEFT);

      personenPruefungStarter.startePersonenPruefung();
    }
  }

  private Direktkandidatur aufruecken(Ersatzkandidatur ersatzkandidaturToReplace, Direktkandidatur uebergeordneteKandidaturToReplace) {
    Direktkandidatur direktkandidatur = direktkandidaturFactory.create();

    copyErsatzkandidaturAndDirektkandidaturAttributes(direktkandidatur, ersatzkandidaturToReplace, uebergeordneteKandidaturToReplace);

    // Nicht mehr relevante Entitäten löschen (Ersatzkandidatur zuerst!).
    delete(ersatzkandidaturToReplace);
    delete(uebergeordneteKandidaturToReplace);

    save(direktkandidatur);

    return direktkandidatur;
  }

  protected void copyErsatzkandidaturAndDirektkandidaturAttributes(Direktkandidatur direktkandidatur, Ersatzkandidatur ersatzkandidaturToReplace, Direktkandidatur direktkandidaturToReplace) {
    // Initial alle Attribute der Direktkandidatur übernehmen.
    List<Wahlrechtspruefung> wahlrechtspruefungenVonDirektkandidatUebernommen = copyDirektkandidaturAttributes(direktkandidatur, direktkandidaturToReplace);

    // Anschließend mit den korrespondierenden Attributen der Ersatzkandidatur überschreiben.
    copyErsatzkandidaturAttributes(direktkandidatur, ersatzkandidaturToReplace);

    // ELECTMUC-2752
    if (wahlrechtspruefungenVonDirektkandidatUebernommen.stream().anyMatch(wahlrechtspruefung -> wahlrechtspruefung.getWahlrechtspruefStatus().isZulassungsbeschraenkend())
        && direktkandidatur.getKandidaturStatus().isZugelassen()) {
      direktkandidatur.setKandidaturStatus(KandidaturStatus.OFFEN);
      direktkandidatur.getDirektkandidat().setWahlvorschlagStatus(WahlvorschlagStatus.OFFEN);
    } else {
      direktkandidatur.getDirektkandidat().setWahlvorschlagStatus(direktkandidatur.getKandidaturStatus().toWahlvorschlagStatus());
    }
  }

  private List<Wahlrechtspruefung> copyDirektkandidaturAttributes(Direktkandidatur direktkandidatur, Direktkandidatur direktkandidaturToReplace) {
    Direktkandidat direktkandidat = direktkandidaturToReplace.getDirektkandidat();

    direktkandidatur.setDirektkandidat(direktkandidat);

    // Wahlrechtsprüfungen des Wahlvorschlags übernehmen
    List<Wahlrechtspruefung> wahlrechtspruefungenUebernommen = new ArrayList<>();
    for (Wahlrechtspruefung wahlrechtspruefung : wahlrechtspruefungDAO.findByKandidatur(direktkandidaturToReplace)) {
      if (wahlrechtspruefung.getPruefkriterium().getPruefkriteriumBezug().isBezugFuer(direktkandidat)) {
        wahlrechtspruefung.setKandidatur(direktkandidatur);
        wahlrechtspruefungenUebernommen.add(wahlrechtspruefung);
      }
    }
    return wahlrechtspruefungenUebernommen;
  }

  private void save(Direktkandidatur direktkandidatur) {
    direktkandidaturDao.persist(direktkandidatur);
  }

  private void delete(Direktkandidatur direktkandidatur) {
    direktkandidaturDao.remove(direktkandidatur);
  }

  private Listenkandidatur aufruecken(Ersatzkandidatur ersatzkandidaturToReplace, Listenkandidatur uebergeordneteKandidaturToReplace) {
    Listenkandidatur listenkandidatur = listenkandidaturFactory.create();

    copyErsatzkandidaturAndListenkandidaturAttributes(listenkandidatur, ersatzkandidaturToReplace, uebergeordneteKandidaturToReplace);

    // Nicht mehr relevante Entitäten löschen (Ersatzkandidatur zuerst!).
    delete(ersatzkandidaturToReplace);
    delete(uebergeordneteKandidaturToReplace);

    save(listenkandidatur);

    return listenkandidatur;
  }

  private void save(Listenkandidatur listenkandidatur) {
    listenkandidaturDao.persist(listenkandidatur);
  }

  private void delete(Listenkandidatur listenkandidatur) {
    listenkandidaturDao.remove(listenkandidatur);
  }

  protected void copyErsatzkandidaturAndListenkandidaturAttributes(Listenkandidatur listenkandidatur, Ersatzkandidatur ersatzkandidaturToReplace, Listenkandidatur listenkandidaturToReplace) {
    // Initial alle Attribute der Listenkandidatur übernehmen.
    copyListenkandidaturAttributes(listenkandidatur, listenkandidaturToReplace);
    // Anschließend mit den korrespondierenden Attributen der Ersatzkandidatur überschreiben.
    copyErsatzkandidaturAttributes(listenkandidatur, ersatzkandidaturToReplace);
  }

  private void copyListenkandidaturAttributes(Listenkandidatur listenkandidatur, Listenkandidatur listenkandidaturToReplace) {
    // ELECT-6621 erst Liste setzen, dann Attribute...
    listenkandidatur.setListe(listenkandidaturToReplace.getListe());

    listenkandidaturToReplace.copyEntityAttributesUsingSetter(listenkandidatur);
  }

  protected void copyErsatzkandidaturAttributes(Kandidatur kandidatur, Ersatzkandidatur ersatzkandidaturToReplace) {
    ersatzkandidaturToReplace.copyEntityAttributesUsingSetter(kandidatur);

    kandidatur.setAnschrift(ersatzkandidaturToReplace.getAnschrift());
    kandidatur.setErreichbarkeitsanschrift(ersatzkandidaturToReplace.getErreichbarkeitsanschrift());
    kandidatur.setKontoverbindung(ersatzkandidaturToReplace.getKontoverbindung());
    kandidatur.setWahl(ersatzkandidaturToReplace.getWahl());
    kandidatur.setWahltermin(ersatzkandidaturToReplace.getWahltermin());
    kandidatur.setZugeordneteErsatzkandidatur(ersatzkandidaturToReplace.getZugeordneteErsatzkandidatur());

    // NOTE, dass CustomData manuell umgehangen werden muss, da deren Implementierung bei Ersatz- und Listenkandidatur
    // nicht identisch ist!

    for (Gewaehlt gewaehlt : ersatzkandidaturToReplace.getGewaehltsByKandidatur()) {
      kandidatur.addGewaehltByKandidatur(gewaehlt);
    }

    kandidatur.setStaatsangehoerigkeitenSorted(ersatzkandidaturToReplace.getStaatsangehoerigkeitenSorted());

    for (String personendatenTag : ersatzkandidaturToReplace.getPersonendatenTag()) {
      kandidatur.addPersonendatenTag(personendatenTag);
    }

    for (PersonenVerknuepfung personenVerknuepfung : ersatzkandidaturToReplace.getPersonenVerknuepfungsByPerson1()) {
      kandidatur.addPersonenVerknuepfungByPerson1(personenVerknuepfung);
    }

    for (PersonenVerknuepfung personenVerknuepfung : ersatzkandidaturToReplace.getPersonenVerknuepfungsByPerson2()) {
      kandidatur.addPersonenVerknuepfungByPerson2(personenVerknuepfung);
    }

    kandidatur.setFoto(ersatzkandidaturToReplace.getFoto());

    // Wahlrechtsprüfungen der Kandidatur übernehmen
    for (Wahlrechtspruefung wahlrechtspruefung : wahlrechtspruefungDAO.findByKandidatur(ersatzkandidaturToReplace)) {
      wahlrechtspruefung.setKandidatur(kandidatur);
    }
  }

  protected Ersatzkandidatur aufruecken(Ersatzkandidatur ersatzkandidatur, Ersatzkandidatur uebergeordneteKandidaturToReplace) {
    ersatzkandidatur.setUebergeordneteKandidatur(uebergeordneteKandidaturToReplace.getUebergeordneteKandidatur());

    delete(uebergeordneteKandidaturToReplace);

    return ersatzkandidatur;
  }

  public void delete(Ersatzkandidatur ersatzkandidatur) {
    ersatzkandidaturDao.remove(ersatzkandidatur);
  }

  public void tryDelete(Kandidatur kandidatur) {
    Kandidatur entity = kandidaturDao.attach(kandidatur);

    if (entity != null) {
      kandidaturDao.remove(entity);
    }
  }

  private Ersatzkandidatur attach(Ersatzkandidatur ersatzkandidatur) {
    return ersatzkandidaturDao.attach(ersatzkandidatur);
  }
}
