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

import static java.util.Arrays.asList;

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

import javax.inject.Inject;

import de.ivu.elect.business.person.entity.PersonStatus;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.personenpruefung.boundary.CommonPersonenKonfliktBoundaryCreate;
import de.ivu.elect.business.personenpruefung.boundary.PersonenKonfliktDAO;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonflikt;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktStatus;

public abstract class AbstractPersonenPruefSchritt implements PersonenPruefSchritt {

  @Inject
  protected transient CommonPersonenKonfliktBoundaryCreate konfliktCreate;

  @Inject
  protected transient PersonenKonfliktDAO personenKonfliktDAO;

  protected AbstractPersonenPruefSchritt() {
    super();
  }

  @Override
  public Map<Personendaten, PersonenKonflikt> pruefe(Collection<Personendaten> personen) {
    Map<Personendaten, PersonenKonflikt> konfliktPerPerson = new HashMap<>(personen.size());

    for (Personendaten personendaten : personen) {
      boolean changed = pruefePerson(personendaten, konfliktPerPerson);

      if (changed && isPruefschrittBrauchtFlush()) {
        flush(); // ELECTMUC-2665
      }
    }

    return konfliktPerPerson;
  }

  protected boolean isPruefschrittBrauchtFlush() {
    return false;
  }

  protected boolean pruefePerson(Personendaten personendaten, Map<Personendaten, PersonenKonflikt> konfliktPerPersonendaten) {
    if (isRelevantPersonendatenInstance(personendaten) && isPotentiellNichtGeeignet(personendaten)) {
      PersonenKonflikt konflikt = findOrCreateKonflikt(personendaten);

      removeAndereManuellZuPruefendeKonflikte(personendaten, konflikt); // ELECT-9251

      updateStatus(personendaten, konflikt);

      konfliktPerPersonendaten.put(personendaten, konflikt);

      return true;
    }

    return removeExistingKonflikt(personendaten);
  }

  private void removeAndereManuellZuPruefendeKonflikte(Personendaten personendaten, PersonenKonflikt konflikt) {
    List<PersonenKonflikt> personenKonflikteManuellZuPruefen = personenKonfliktDAO.findByPersonAndKonfliktStatus(personendaten, asList(PersonenKonfliktStatus.MANUELL_ZU_PRUEFEN));

    for (PersonenKonflikt personenKonfliktManuellZuPruefen : personenKonflikteManuellZuPruefen) {
      if (!personenKonfliktManuellZuPruefen.equals(konflikt)) {
        personenKonfliktDAO.remove(personenKonfliktManuellZuPruefen);
      }
    }
  }

  protected void updateStatus(Personendaten personendaten, PersonenKonflikt konflikt) {
    if (konflikt.isKonfliktStatusManuellZuPruefen()) {
      personendaten.setPersonStatus(PersonStatus.MANUELL_ZU_PRUEFENDER_KONFLIKT_VORHANDEN);
    }

    if (konflikt.isKonfliktStatusAblehnungsgrund()) {
      personendaten.setPersonStatus(PersonStatus.NICHT_GEEIGNET);
    }
  }

  protected boolean isRelevantPersonendatenInstance(Personendaten personendaten) {
    if (personendaten != null) {
      for (Class< ? extends Personendaten> clazz : getRelevantPersonendatenClasses()) {
        if (personendaten.isInstanceOf(clazz)) {
          return true;
        }
      }
    }

    return false;
  }

  protected PersonenKonflikt findOrCreateKonflikt(Personendaten personendaten) {
    return konfliktCreate.findOrCreate(personendaten, getPersonenKonfliktArt(), getPersonenKonfliktStatus());
  }

  protected boolean removeExistingKonflikt(Personendaten personendaten) {
    return konfliktCreate.removeByPersonAndKonfliktArt(personendaten, getPersonenKonfliktArt());
  }

  protected void flush() {
    personenKonfliktDAO.flush();
  }
}
