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

import static java.util.Objects.nonNull;


import java.util.List;
import java.util.Optional;

import javax.inject.Inject;

import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.VerknuepfungsArt;
import de.ivu.elect.business.person.entity.VerknuepfungsGrundlage;
import de.ivu.elect.business.person.entity.VerknuepfungsStatus;

public class PersonendatenVerknuepfer {

  @Inject
  private PersonenVerknuepfungDAO personenVerknuepfungDao;

  public PersonendatenVerknuepfer() {
    super();
  }

  public PersonenVerknuepfung verknuepfeMaschinell(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another,
      VerknuepfungsStatus verknuepfungsStatus) {
    return verknuepfe(verknuepfungsArt, one, another, VerknuepfungsGrundlage.MASCHINELL, verknuepfungsStatus);
  }

  public PersonenVerknuepfung verknuepfeManuell(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another,
      VerknuepfungsStatus verknuepfungsStatus) {
    return verknuepfe(verknuepfungsArt, one, another, VerknuepfungsGrundlage.MANUELL, verknuepfungsStatus);
  }

  public PersonenVerknuepfung verknuepfe(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another,
      VerknuepfungsGrundlage verknuepfungsGrundlage, VerknuepfungsStatus verknuepfungsStatus) {
    return presetPersonenVerknuepfung(createPersonenVerknuepfung(verknuepfungsArt, one, another), verknuepfungsGrundlage,
        verknuepfungsStatus);
  }

  public PersonenVerknuepfung verknuepfeAndPersistMaschinell(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another,
                                                             VerknuepfungsStatus verknuepfungsStatus) {
    return verknuepfeAndPersist(verknuepfungsArt, one, another, VerknuepfungsGrundlage.MASCHINELL, verknuepfungsStatus);
  }

  public PersonenVerknuepfung verknuepfeAndPersistManuell(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another, VerknuepfungsStatus verknuepfungsStatus) {
    return verknuepfeAndPersist(verknuepfungsArt, one, another, VerknuepfungsGrundlage.MANUELL, verknuepfungsStatus);
  }

  public PersonenVerknuepfung verknuepfeAndPersist(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another, VerknuepfungsGrundlage verknuepfungsGrundlage, VerknuepfungsStatus verknuepfungsStatus) {
    PersonenVerknuepfung personenVerknuepfung = presetPersonenVerknuepfung(findOrCreatePersonenVerknuepfung(verknuepfungsArt, one, another),
        verknuepfungsGrundlage, verknuepfungsStatus);

    if (!personenVerknuepfung.isPersistent()) {
      personenVerknuepfungDao.persist(personenVerknuepfung);
    }

    return personenVerknuepfung;
  }

  private PersonenVerknuepfung findOrCreatePersonenVerknuepfung(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another) {
    return findPersonenVerknuepfung(verknuepfungsArt, one, another).orElse(createPersonenVerknuepfung(verknuepfungsArt, one, another));
  }

  private Optional<PersonenVerknuepfung> findPersonenVerknuepfung(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another) {
    if (one.getId()==null || another.getId() == null) {
      return Optional.empty();
    }

    // ELECT-11469 Verfahren, dass häufiger den Finder-Cache nutzt, vorher siehe unten

    // Kleinere Id nach vorne um möglichst früh den Cache zu treffen
    Personendaten p1 = one;
    Personendaten p2 = another;
    if (another.getId() < one.getId()) {
      p1 = another;
      p2 = one;
    }

    for (PersonenVerknuepfung personenVerknuepfung : personenVerknuepfungDao.findByNurPerson1(p1)) {
      if (personenVerknuepfung.getPerson2().equals(p2)) {
        return Optional.of(personenVerknuepfung);
      }
    }
    for (PersonenVerknuepfung personenVerknuepfung : personenVerknuepfungDao.findByNurPerson1(p2)) {
      if (personenVerknuepfung.getPerson2().equals(p1)) {
        return Optional.of(personenVerknuepfung);
      }
    }
    // vor ELECT-11469 return personenVerknuepfungDao.findByPersonen(/* WASDE-1549 verknuepfungsArt, */one, another).stream().findFirst();
    return Optional.empty();
  }

  private PersonenVerknuepfung createPersonenVerknuepfung(VerknuepfungsArt verknuepfungsArt, Personendaten one, Personendaten another) {
    PersonenVerknuepfung personenVerknuepfung = new PersonenVerknuepfung();
    personenVerknuepfung.setVerknuepfungsArt(verknuepfungsArt);

    if (nonNull(one) && nonNull(another)) {
      personenVerknuepfung.setPersonen(one, another);
    } else {
      if (nonNull(one)) {
        personenVerknuepfung.setPerson1(one);
      }

      if (nonNull(another)) {
        personenVerknuepfung.setPerson2(another);
      }
    }

    return personenVerknuepfung;
  }

  private PersonenVerknuepfung presetPersonenVerknuepfung(PersonenVerknuepfung personenVerknuepfung, VerknuepfungsGrundlage verknuepfungsGrundlage, VerknuepfungsStatus verknuepfungsStatus) {
    personenVerknuepfung.setVerknuepfungsGrundlage(verknuepfungsGrundlage);
    personenVerknuepfung.setVerknuepfungsStatus(verknuepfungsStatus);
    return personenVerknuepfung;
  }
}
