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

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import javax.faces.validator.LongRangeValidator;
import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartExtendedDAO;
import de.ivu.elect.business.gebietsbaum.control.GebietByBreadthFirstComparator;
import de.ivu.elect.business.gruppe.boundary.GruppeExtendedDAO;
import de.ivu.elect.business.gruppe.entity.GruppeArt;
import de.ivu.elect.business.internet.control.InternetWidgetCustomDataFactory;
import de.ivu.elect.business.internet.entity.InternetSeiteTyp;
import de.ivu.elect.business.internet.entity.InternetWidget;
import de.ivu.elect.business.internet.entity.InternetWidgetBreite;
import de.ivu.elect.business.internet.entity.InternetWidgetCustomData;
import de.ivu.elect.business.internet.entity.InternetWidgetPropertyContext;
import de.ivu.elect.business.internet.entity.InternetWidgetStatus;
import de.ivu.elect.business.internet.entity.InternetWidgetTyp;
import de.ivu.elect.business.internet.entity.InternetWidgetTypCustomDataKategorie;
import de.ivu.elect.business.wahl.boundary.WahlExtendedDAO;
import de.ivu.elect.business.wahl.boundary.WahlartExtendedDAO;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.FacesMessageUtil;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.AbstractLongProperty;
import de.ivu.elect.jee.presentation.dynamicform.AbstractStringProperty;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaEnumProperty;
import de.ivu.elect.jee.presentation.dynamicform.Property;
import de.ivu.elect.jee.presentation.dynamicform.PropertyType;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;


import static java.util.stream.Collectors.toList;

public class InternetWidgetViewFormBuilder {

  @Inject
  private transient InternetWidgetCustomDataFactory internetWidgetCustomDataFactory;

  @Inject
  private transient Messages messages;

  @Inject
  private transient GruppeExtendedDAO gruppeExtendedDAO;

  @Inject
  private transient GebietExtendedDAO gebietExtendedDAO;

  @Inject
  private transient WahlExtendedDAO wahlExtendedDAO;

  @Inject
  private transient WahlartExtendedDAO wahlartExtendedDAO;

  @Inject
  private transient GebietNummerFormatter gebietNummerFormatter;

  @Inject
  private transient GebietsartExtendedDAO gebietsartExtendedDAO;

  public void addProperties(FormBuilder formBuilder, InternetWidget internetWidget) {
    InternetWidgetCustomData internetWidgetCustomData = null;
    InternetSeiteTyp seitenTyp = internetWidget.getInternetSeite().getSeitenTyp();

    if (internetWidget.getCustomData() instanceof InternetWidgetCustomData) {
      internetWidgetCustomData = (InternetWidgetCustomData) internetWidget.getCustomData();
    }

    Long initialeZeile = internetWidget.getZeile();
    InternetWidgetBreite initialaBreite = internetWidget.getBreite();

    LambdaEnumProperty<InternetWidgetTyp> widgetTypMitLeererAuswahlProperty = internetWidget.getProperties().getWidgetTypMitLeererAuswahlProperty();

    widgetTypMitLeererAuswahlProperty.setItemIconMapper((icons, internetWidgetTyp) -> internetWidgetTyp.getIcon());

    Predicate<InternetWidgetTyp> internetWidgetTypPredicate = internetWidgetCustomDataFactory::isSupported;

    boolean slideshow = seitenTyp.isSlideshow();
    if (slideshow) {
      internetWidgetTypPredicate = x -> internetWidgetCustomDataFactory.isSupported(x) && x.isSupportsSlideShow();
    }

    widgetTypMitLeererAuswahlProperty.setValueFilter(internetWidgetTypPredicate);

    formBuilder.addProperty(widgetTypMitLeererAuswahlProperty).withReadonly(internetWidgetCustomData != null);
    AbstractStringProperty sprungmarkeProperty = internetWidget.getProperties().getSprungmarkeProperty();

    sprungmarkeProperty.appendObservedPropertyValueChangedConsumer(other -> {
      if (other.equals(widgetTypMitLeererAuswahlProperty)) {
        if (!widgetTypMitLeererAuswahlProperty.hasValue()) {
          sprungmarkeProperty.setValue(null);
        } else {
          sprungmarkeProperty.setValue(messages.getMessageForMessageKey(widgetTypMitLeererAuswahlProperty.getValue().getSprungmarkeMsgKey()));
        }
      }
    });

    if (internetWidgetCustomData != null && internetWidget.getStatus().isKonfigurationNotwendig()) {
      internetWidget.setStatus(InternetWidgetStatus.AKTIV);
    }

    LambdaEnumProperty<InternetWidgetStatus> statusProperty = internetWidget.getProperties().getStatusProperty();
    statusProperty.setValueFilter(InternetWidgetStatus::isManuellAuswaehlbar);
    formBuilder.addProperty(statusProperty).withReadonly(internetWidgetCustomData == null);
    formBuilder.addProperty(sprungmarkeProperty).withObservedProperty(widgetTypMitLeererAuswahlProperty);
    formBuilder.addProperty(internetWidget.getProperties().getBeschreibungProperty()).withType(PropertyType.INPUT_TEXTAREA);


    formBuilder.addSeparator("internet.widget.edit.position.separator");
    AbstractLongProperty zeileProperty = internetWidget.getProperties().getZeileProperty();

    zeileProperty.appendObservedPropertyValueChangedConsumer(other -> {
      if (other.equals(widgetTypMitLeererAuswahlProperty)) {
        if (widgetTypMitLeererAuswahlProperty.hasValue() && widgetTypMitLeererAuswahlProperty.getValue().isHeaderWidget()) {
          zeileProperty.setValue(0L);
          zeileProperty.setReadonly(true);
        } else {
          zeileProperty.setValue(initialeZeile);
          zeileProperty.setReadonly(false);
        }
      }
    });
    formBuilder.addProperty(zeileProperty).withObservedProperty(widgetTypMitLeererAuswahlProperty);
    if (slideshow) {
      formBuilder.withLabel(messages.getMessageForMessageKey("internet.widget.zeile.slideshow.seite"));
      formBuilder.withValidator(new LongRangeValidator(99L, 1L));
    } else {
      formBuilder.withValidator(new LongRangeValidator(99L, 0L));
    }
    formBuilder.addProperty(internetWidget.getProperties().getPositionProperty());
    LambdaEnumProperty<InternetWidgetBreite> breiteMitLeererAuswahlProperty = internetWidget.getProperties().getBreiteMitLeererAuswahlProperty();
    breiteMitLeererAuswahlProperty.appendObservedPropertyValueChangedConsumer(other->{
      if (other.equals(widgetTypMitLeererAuswahlProperty)) {
        InternetWidgetTyp value = widgetTypMitLeererAuswahlProperty.getValue();
        if (value == null) {
          breiteMitLeererAuswahlProperty.setReadonly(false);
          breiteMitLeererAuswahlProperty.setValue(initialaBreite);
        } else {
          breiteMitLeererAuswahlProperty.setReadonly(value.isBreiteFixiert());
          breiteMitLeererAuswahlProperty.setValue(value.getInitialeBreite());
        }
      }
    });



    formBuilder.addProperty(breiteMitLeererAuswahlProperty).withObservedProperty(widgetTypMitLeererAuswahlProperty);


    if (internetWidgetCustomData != null) {

      Wahl wahl = internetWidget.getInternetSeite().getWahl();
      Map<InternetWidgetTypCustomDataKategorie, List<Property>> kriteriumProperties = internetWidgetCustomData
          .getProperties(new InternetWidgetPropertyContext(messages, //
              wahlExtendedDAO.attach(wahl), //
              seitenTyp, //
              () -> gruppeExtendedDAO.findByWahlAndGruppeArten(wahl, GruppeArt.valuesPolitischeGruppeGruppeArt()),
              () -> gebietExtendedDAO.findByWahl(wahl).stream().sorted(new GebietByBreadthFirstComparator()).collect(toList()),
              gebietNummerFormatter, //
              () -> wahlartExtendedDAO.findByAllOrderByName(wahl.getMandant()),
              ()->gebietsartExtendedDAO.findByAll(wahl.getMandant())
          ));

      kriteriumProperties.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEach(e -> {

        formBuilder.addSeparator(FacesMessageUtil.getEnumMessageKey(e.getKey()));

        for (Property kriteriumProperty : e.getValue()) {
          formBuilder.addProperty(kriteriumProperty);
        }
      });
    }

  }
}
