
package de.ivu.elect.presentation.wahlvorschlag.form;

import java.util.Date;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;

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

import de.ivu.elect.business.person.entity.NlPersonendaten;
import de.ivu.elect.business.person.entity.NlPersonendatenProperties;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.wahl.control.AbstractNlExportArtefaktNachSystemExportstatusExportContext;
import de.ivu.elect.business.wahl.entity.AbstractWahlParameterLoader;
import de.ivu.elect.business.wahl.entity.NlWahlParameterWerte;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlParameterExtendedLoader;
import de.ivu.elect.business.wahlvorschlag.boundary.WahlvorschlagEmpfangsquittungDokumentContext;
import de.ivu.elect.business.wahlvorschlag.boundary.WahlvorschlagExtendedDAO;
import de.ivu.elect.business.wahlvorschlag.entity.NlListe;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlagsperson.boundary.WahlvorschlagsPersonExtendedDAO;
import de.ivu.elect.business.wahlvorschlagsperson.entity.WahlvorschlagsPerson;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaDateProperty;
import de.ivu.elect.jee.presentation.dynamicform.LambdaStringProperty;
import de.ivu.elect.jee.presentation.dynamicform.PropertyType;

@Specializes // ELECT-10119
public class NlWahlvorschlagEmpfangsquittungDokumentErzeugenViewFormBuilder extends WahlvorschlagEmpfangsquittungDokumentErzeugenViewFormBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient WahlvorschlagExtendedDAO wahlvorschlagExtendedDAO;

  @Inject
  private transient WahlvorschlagsPersonExtendedDAO wahlvorschlagsPersonExtendedDAO;

  @Inject
  private transient WahlParameterExtendedLoader wahlParameterExtendedLoader;

  public NlWahlvorschlagEmpfangsquittungDokumentErzeugenViewFormBuilder() {
    super();
  }

  @Override
  public void addProperties(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context) {
    addProperties(formBuilder, context, false);
  }

  private void addProperties(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context, boolean readonly) {
    addPropertiesEmpfaenger(formBuilder, context, readonly);

    addPropertiesEinreichung(formBuilder, context, readonly);
  }

  private void addPropertiesEinreichung(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context, boolean readonly) {
    formBuilder.addSeparator(AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLVORSCHLAG_EINREICHUNG_SEPARATOR_MSG_KEY);

    initContextAndAddDateProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLVORSCHLAG_EINREICHUNG_ABGABEFRIST, readonly);
    initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLVORSCHLAG_EINREICHUNG_UNTERZEICHNER_1_NAME, readonly);
    initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLVORSCHLAG_EINREICHUNG_ANSCHRIFT_ORT, readonly);

    // ELECT-10119
    // initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLBEHOERRDE_WAHLLEITER_NAME, readonly);
    // initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLBEHOERDE_ANSCHRIFT_STRASSE_HAUSNUMMER, readonly);
    // initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLBEHOERDE_ANSCHRIFT_PLZ, readonly);
    // initContextAndAddStringProperty(formBuilder, context, AbstractNlExportArtefaktNachSystemExportstatusExportContext.WAHLBEHOERDE_ANSCHRIFT_ORT, readonly);
  }

  private void addPropertiesEmpfaenger(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context, boolean readonly) {
    formBuilder.addSeparator("wahlvorschlag.empfangsquittung.empfaenger.separator.label");

    Wahlvorschlag wahlvorschlag = wahlvorschlagExtendedDAO.attach(context.getWahlvorschlag());

    Personendaten empfaenger = context.getEmpfaenger();

    if (wahlvorschlag != null) {
      Optional<WahlvorschlagsPerson> beauftragter = wahlvorschlagsPersonExtendedDAO.findByWahlvorschlagOhneUnterstuetzer(wahlvorschlag).stream() //
          .filter(wahlvorschlagsPerson -> wahlvorschlagsPerson.isWahlvorschlagsPersonTyp(NlListe.LISTENBEAUFTRAGTER)) //
          .findFirst();

      beauftragter.ifPresent(wahlvorschlagsPerson -> wahlvorschlagsPerson.copyPersonendatenTo(empfaenger)); // ELECT-10723
    }

    NlPersonendatenProperties empfaengerProperties = new NlPersonendaten(empfaenger).getProperties();
    formBuilder.addProperty(empfaengerProperties.getFamiliennameProperty()).withReadonly(readonly).required(); // ELECT-10582
    formBuilder.addProperty(empfaengerProperties.getInitialenProperty()).withReadonly(readonly).required(); // ELECT-10582
    formBuilder.addProperty(empfaengerProperties.getVornameProperty()).withReadonly(readonly);
  }

  private void initContextAndAddStringProperty(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context, NlWahlParameterWerte parameter, boolean readonly) {
    initContextAndAddProperty(context, parameter, String.class, parameter::getStringValue, (setter, getter) -> addStringProperty(formBuilder, parameter, setter, getter, readonly));
  }

  private void addStringProperty(FormBuilder formBuilder, NlWahlParameterWerte parameter, Consumer<String> setter, Supplier<String> getter, boolean readonly) {
    int maxLength = parameter.getDefaultMaxLength();

    formBuilder.addProperty(new LambdaStringProperty(parameter.getDefaultLabel(getMessages()), parameter.isDefaultRequired(), setter, getter, parameter.getDefaultMinLength(), maxLength)).withReadonly(readonly);

    if (maxLength > NlWahlParameterWerte.MAX_LENGTH_DEFAULT_VALUE) {
      formBuilder.withType(PropertyType.INPUT_TEXTAREA);
    }
  }

  private void initContextAndAddDateProperty(FormBuilder formBuilder, WahlvorschlagEmpfangsquittungDokumentContext context, NlWahlParameterWerte parameter, boolean readonly) {
    initContextAndAddProperty(context, parameter, Date.class, parameter::getDateValue, (setter, getter) -> addDateProperty(formBuilder, parameter, setter, getter, readonly));
  }

  private void addDateProperty(FormBuilder formBuilder, NlWahlParameterWerte parameter, Consumer<Date> setter, Supplier<Date> getter, boolean readonly) {
    formBuilder.addProperty(new LambdaDateProperty(parameter.getDefaultLabel(getMessages()), parameter.isDefaultRequired(), setter, getter)).withReadonly(readonly);
  }

  private <C> void initContextAndAddProperty(WahlvorschlagEmpfangsquittungDokumentContext context, NlWahlParameterWerte parameter, Class<C> parameterValueClass,
      BiFunction<Wahl, AbstractWahlParameterLoader, C> parameterValueGetter, BiConsumer<Consumer<C>, Supplier<C>> propertyFct) {
    String key = parameter.name();

    // Werte im WahlvorschlagEmpfangsquittungDokumentContext halten und nach Erzeugung in DB übernehmen, cf. NlWahlvorschlagEmpfangsquittungDokumentGenerator#createDateiExport!
    Consumer<C> setter = value -> context.put(key, value);
    Supplier<C> getter = () -> context.get(key, parameterValueClass);

    if (!context.containsKey(key)) {
      setter.accept(parameterValueGetter.apply(context.getWahl(), wahlParameterExtendedLoader));
    }

    propertyFct.accept(setter, getter);
  }
}
