
package de.ivu.elect.dokumente;

import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toSet;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

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

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentMethod;
import de.ivu.document.generator.template.annotations.DocumentParam;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.person.entity.AbstractPersonendaten;
import de.ivu.elect.business.person.entity.Geschlecht;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.presentation.person.PersonendatenFormatter;

// Cf. de.ivu.elect.dokumente.meldedaten.MeldedatenEintragBaseDocument!
// Cf. de.ivu.elect.dokumente.waehlerverzeichnis.WaehlerverzeichnisEintragBaseDocument!
// Cf. de.ivu.elect.dokumente.wahlschein.WahlscheinantragDocument!
public class PersonBasisDokument extends BaseDocument {

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

  private static final long serialVersionUID = 1L;

  @DocumentSimpleField("ID")
  public final Long id;

  @DocumentSimpleField("Ordnungsmerkmal")
  public final String ordnungsmerkmal;

  @DocumentSimpleField("Externe ID")
  public final String externeId;

  @DocumentSimpleField("Anrede")
  public final String anrede;

  @DocumentSimpleField("Anrede-Anschrift")
  public final String anredeAnschrift;

  @DocumentSimpleField("Anrede-Anschreiben")
  public final String anredeFormel;

  @DocumentSimpleField("Titel")
  public final String titel;

  @DocumentSimpleField("Akademische Grade")
  public final String akademischeGradeKommasepariert;

  /**
   * @deprecated
   * @see PersonBasisDokument#familiennameBestandteil
   */
  @Deprecated
  @DocumentSimpleField("Namensbestandteile")
  public final String namensbestandteile;

  @DocumentSimpleField("Namensbestandteile")
  public final String familiennameBestandteil;

  /**
   * @deprecated
   * @see PersonBasisDokument#familienname
   */
  @Deprecated
  @DocumentSimpleField("Nachname")
  public final String nachname;

  @DocumentSimpleField("Familienname")
  public final String familienname;

  @DocumentSimpleField("Rufname")
  public final String vorname;

  /**
   * @deprecated
   * @see PersonBasisDokument#vornamen
   */
  @Deprecated
  @DocumentSimpleField("VornamenVollstaendig")
  public final String vornamenVollsteandig;

  @DocumentSimpleField("Vornamen")
  public final String vornamen;

  @DocumentSimpleField("Geburtsdatum")
  public final String geburtsdatum;

  /**
   * @deprecated
   * @see PersonBasisDokument#geburtsjahr
   */
  @Deprecated
  @DocumentSimpleField("JahrDerGeburt")
  public final String jahrDerGeburt;

  @DocumentSimpleField("Geburtsjahr")
  public final Long geburtsjahr;

  @DocumentSimpleField("Geburtsort")
  public final String geburtsort;

  @DocumentSimpleField("Geschlecht")
  public final String geschlecht;

  @DocumentSimpleField("Geschlecht-Ist-Maennlich")
  public final boolean geschlechtMaennlich;

  @DocumentSimpleField("Geschlecht-Ist-Weiblich")
  public final boolean geschlechtWeiblich;

  @DocumentSimpleField("Geschlecht-Ist-Divers")
  public final boolean geschlechtDivers;

  @DocumentSimpleField("Geschlecht-Ist-Unbekannt")
  public final boolean geschlechtUnbekannt;

  @DocumentSimpleField("Berufschluessel")
  public final String berufsschluessel;

  /**
   * @deprecated
   * @see PersonBasisDokument#berufeKommasepariert
   */
  @Deprecated
  @DocumentSimpleField("BerufOderFunktion")
  public final String beruf;

  @DocumentSimpleField("Berufe")
  public final String berufeKommasepariert;

  @DocumentSimpleField("Ehrenaemter")
  public final String ehrenaemterKommasepariert;

  private final List<String> personendatenTags;

  @DocumentSimpleField("Label")
  public final String personendatenTagsKommasepariert;

  @DocumentSimpleField("TitelUndNachname")
  public final String titelUndNachname;

  @DocumentSimpleField("TitelNamensbestandteileUndNachname")
  public final String titelNamensbestandteileUndNachname;

  @DocumentSimpleField("TitelVornameNamensbestandteileUndNachname")
  public final String titelVornameNamensbestandteileUndNachname;

  @DocumentSimpleField("TitelVornamenVollstaendigNamensbestandteileUndNachname")
  public final String titelVornamenVollstaendigNamensbestandteileUndNachname;

  @DocumentSimpleField("AkadGradTitelUndNachname")
  public final String akadGradTitelUndNachname;

  protected PersonBasisDokument() {
    super();

    this.id = null;

    this.ordnungsmerkmal = "";
    this.externeId = "";

    this.anrede = "";
    this.anredeAnschrift = "";
    this.anredeFormel = "";

    this.titel = "";

    this.akademischeGradeKommasepariert = "";

    this.familiennameBestandteil = "";
    this.namensbestandteile = this.familiennameBestandteil;
    this.familienname = "";
    this.nachname = this.familienname;

    this.vorname = "";
    this.vornamen = "";
    this.vornamenVollsteandig = this.vornamen;

    this.geburtsdatum = "";
    this.geburtsjahr = null;
    this.jahrDerGeburt = "";
    this.geburtsort = "";

    this.geschlecht = "";
    this.geschlechtMaennlich = false;
    this.geschlechtWeiblich = false;
    this.geschlechtDivers = false;
    this.geschlechtUnbekannt = true;

    this.berufsschluessel = "";

    this.berufeKommasepariert = "";
    this.beruf = this.berufeKommasepariert;

    this.ehrenaemterKommasepariert = "";

    this.personendatenTags = new ArrayList<>();
    this.personendatenTagsKommasepariert = "";

    /*
     * NICHT mehr erweitern, cf. DokumentFormatter#formatGesetzteWerteOderLeerwertSepariert!
     */
    this.titelUndNachname = "";
    this.titelNamensbestandteileUndNachname = "";
    this.titelVornameNamensbestandteileUndNachname = "";
    this.titelVornamenVollstaendigNamensbestandteileUndNachname = "";
    this.akadGradTitelUndNachname = "";
  }

  public PersonBasisDokument(BaseElectContext baseElectContext, Personendaten personendaten) {
    super();

    this.id = personendaten.getId();

    this.ordnungsmerkmal = personendaten.getOrdnungsmerkmal();
    this.externeId = personendaten.getExterneId();

    PersonendatenFormatter personendatenFormatter = baseElectContext.getPersonendatenFormatter();

    // ELECT-9130
    this.anrede = personendatenFormatter.bestimmeAnrede(personendaten);
    this.anredeAnschrift = personendatenFormatter.bestimmeAnredeAnschrift(personendaten);
    this.anredeFormel = personendatenFormatter.bestimmeAnredeFormel(personendaten);

    this.titel = personendaten.getTitel();

    this.akademischeGradeKommasepariert = personendaten.getAkademischeGradeCommaSeparated();

    this.familienname = personendaten.getFamilienname();
    this.nachname = this.familienname;
    this.familiennameBestandteil = personendaten.getFamiliennameBestandteil();
    this.namensbestandteile = this.familiennameBestandteil;

    this.vorname = personendatenFormatter.getVornameAnzeige(personendaten);
    this.vornamen = personendatenFormatter.getVornamenVollstaendigAnzeige(personendaten);
    this.vornamenVollsteandig = this.vornamen;

    if (personendaten.getGeburtsdatum() == null) {
      this.geburtsdatum = null;
      this.geburtsjahr = null;
      this.jahrDerGeburt = null;
    } else {
      this.geburtsdatum = new SimpleDateFormat("dd.MM.yyyy").format(personendaten.getGeburtsdatum());
      this.geburtsjahr = personendaten.getGeburtsjahr();
      this.jahrDerGeburt = this.geburtsjahr.toString();
    }

    if (personendaten.getGeburtsort() == null) {
      this.geburtsort = "";
    } else {
      this.geburtsort = personendaten.getGeburtsort();
    }

    Geschlecht geschlecht = personendaten.getGeschlecht(); // ELECTKOM-626

    this.geschlecht = baseElectContext.getMessage(geschlecht);
    this.geschlechtMaennlich = Geschlecht.MAENNLICH.equals(geschlecht);
    this.geschlechtWeiblich = Geschlecht.WEIBLICH.equals(geschlecht);
    this.geschlechtDivers = Geschlecht.DIVERS.equals(geschlecht);
    this.geschlechtUnbekannt = !this.geschlechtMaennlich && !this.geschlechtWeiblich && !this.geschlechtDivers;

    this.berufsschluessel = personendaten.getBerufsschluessel();

    this.berufeKommasepariert = personendaten.getBerufeCommaSeparated();
    this.beruf = this.berufeKommasepariert;

    this.ehrenaemterKommasepariert = personendaten.getEhrenaemterCommaSeparated();

    this.personendatenTags = personendaten.getPersonendatenTagsSortiert();
    this.personendatenTagsKommasepariert = String.join(AbstractPersonendaten.ATTRIBUTE_AS_DISPLAY_STRING_SEPARATOR, personendaten.getPersonendatenTagsSortiert());

    /*
     * NICHT mehr erweitern, cf. DokumentFormatter#formatGesetzteWerteOderLeerwertSepariert!
     */
    this.titelUndNachname = personendatenFormatter.bestimmeTitelUndNachname( //
        personendaten.getTitel(), //
        personendaten.getFamilienname());
    this.titelNamensbestandteileUndNachname = personendatenFormatter.bestimmeTitelNamensbestandteileUndNachname( //
        personendaten.getTitel(), //
        personendaten.getFamiliennameBestandteil(), //
        personendaten.getFamilienname());
    this.titelVornameNamensbestandteileUndNachname = personendatenFormatter.bestimmeTitelVornameNamensbestandteileUndNachname( //
        personendaten.getTitel(), //
        personendatenFormatter.getVornameAnzeige(personendaten), //
        personendaten.getFamiliennameBestandteil(), //
        personendaten.getFamilienname());
    this.titelVornamenVollstaendigNamensbestandteileUndNachname = personendatenFormatter.bestimmeTitelVornameNamensbestandteileUndNachname( //
        personendaten.getTitel(), //
        personendatenFormatter.getVornamenVollstaendigAnzeige(personendaten), //
        personendaten.getFamiliennameBestandteil(), //
        personendaten.getFamilienname());
    this.akadGradTitelUndNachname = personendatenFormatter.bestimmeAkademischerGradTitelNamensbestandteileUndNachname( //
        personendaten.getAkademischerGradAsList(), //
        personendaten.getTitel(), //
        personendaten.getFamiliennameBestandteil(), //
        personendaten.getFamilienname());
  }

  @DocumentMethod
  public boolean hasAnyLabel(@DocumentParam("values") Object values) {
    return collectValues(values).stream().anyMatch(personendatenTags::contains);
  }

  @DocumentMethod
  public boolean hasAllLabel(@DocumentParam("values") Object values) {
    return personendatenTags.containsAll(collectValues(values));
  }

  private Collection<String> collectValues(Object values) {
    if (values != null) {
      Collection<Object> result = new HashSet<>();

      try {
        if (values.getClass().isArray()) {
          result.addAll(asList((Object[]) values));
        } else if (values instanceof Collection) {
          result.addAll((Collection< ? >) values);
        } else {
          result.add(values); // Bspw. einzelner String...
        }

        return result.stream().filter(Objects::nonNull).map(Object::toString).collect(toSet());
      } catch (Exception ex) {
        LOG.error("Zugriff fehlgeschlagen [" //
            + "values = " + values + ", " //
            + "values instanceof Array = " + values.getClass().isArray() + ", " //
            + "values instanceof Collection = " + (values instanceof Collection) //
            + "]", ex);
      }
    }

    return emptySet();
  }

  protected Long fixNullToZero(Long value) {
    if (value == null) {
      return 0L;
    }

    return value;
  }
}
