
package de.ivu.elect.presentation.gebietsbaum;

import de.ivu.elect.business.gebietsbaum.boundary.GebietSessionSelect;
import de.ivu.elect.business.gebietsbaum.boundary.GebietUebernehmen;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.GebietConstants;
import de.ivu.elect.business.gebietsbaum.entity.GebietUebernehmenParameter;
import de.ivu.elect.business.gebietsbaum.entity.GebietUebernehmenResult;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaBooleanProperty;
import de.ivu.elect.jee.presentation.dynamicform.PropertyType;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.AbstractElectCreateView;
import de.ivu.elect.presentation.LambdaEntitySelectManyProperty;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.gebietsbaum.tree.AbstractNoStoreGebietsbaumView;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.wahl.form.WahlListeInSelectOneMenuFuerEntityUebernahmeBuilder;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;

@RequestScoped
@Named(GebietUebernehmenView.COMPONENT_NAME)
@View(viewId = GebietUebernehmenView.VIEW_ID, useCase = UseCasePermission.GEBIET_UEBERNEHMEN)
@OnlineHilfeId("732")
public class GebietUebernehmenView extends AbstractElectCreateView<GebietUebernehmenParameter> {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "gebietUebernehmenView";

  public static final String VIEW_ID = "/gebietsbaum/gebiet-uebernehmen.xhtml";

  public static final String PARENT_VIEW_ID = GebietSearchView.VIEW_ID;

  @Inject
  private transient GebietsartExtendedDAO gebietsartExtendedDAO;

  @Inject
  private transient GebietUebernehmen gebietUebernehmen;

  @Inject
  private transient AbstractNoStoreGebietsbaumView gebietsbaumView;

  @Inject
  private transient GebietSessionSelect gebietSessionSelect;

  @Inject
  private transient WahlListeInSelectOneMenuFuerEntityUebernahmeBuilder wahlListeInSelectOneMenuFuerEntityUebernahmeBuilder;

  private GebietUebernehmenParameter entity;

  public GebietUebernehmenView() {
    super();
  }

  @PreConditionCheck
  public String checkCondition() {
    if (!isWahlSelected()) {
      return cancel();
    }

    return null;
  }

  @PostConstruct
  public void init() {
    GebietUebernehmenParameter gebietUebernehmenParameter = new GebietUebernehmenParameter();
    gebietUebernehmenParameter.setWahlZiel(getSelectedWahl());
    gebietUebernehmenParameter.setGebietsartenZuUebernehmen(new ArrayList<>(findeGebietsartenZurAuswahl()));

    setEntity(gebietUebernehmenParameter);
  }

  protected List<Gebietsart> findeGebietsartenZurAuswahl() {
    Wahl selectedWahl = getSelectedWahl();
    if (selectedWahl == null) {
      return Collections.emptyList();
    }
    return gebietsartExtendedDAO.findByAllOrderByPosition(selectedWahl.getMandant()).stream().filter(this::isZurAuswahl).collect(toList());
  }

  protected boolean isZurAuswahl(Gebietsart gebietsart) {
    return true;
  }

  @Override
  protected GebietUebernehmenParameter getEntity() {
    return entity;
  }

  protected void setEntity(GebietUebernehmenParameter entity) {
    this.entity = entity;
  }

  @Override
  protected void addProperties(FormBuilder formBuilder, GebietUebernehmenParameter entity) {
    wahlListeInSelectOneMenuFuerEntityUebernahmeBuilder.addProperties(formBuilder, getEntity(), "gebiet.uebernehmen.quell.wahl");

    List<Gebietsart> gebietsarten = findeGebietsartenZurAuswahl();

    formBuilder.addProperty(new LambdaEntitySelectManyProperty<>(gebietsarten, PropertyType.SELECT_MANY_CHECKBOX, getEntity()::setGebietsartenZuUebernehmen, getEntity()::getGebietsartenZuUebernehmen,
        g -> getNameFuerGebietsart(gebietsartExtendedDAO.attach(g)), "gebiet.uebernehmen.gebietsarten", true));

    formBuilder.addProperty(new LambdaBooleanProperty(getMessage("gebiet.uebernehmen.gebiete.aktualisieren"), true, true, getEntity()::setGebieteAktualisierenWennSchonVorhanden,
        getEntity()::isGebieteAktualisierenWennSchonVorhanden));

    formBuilder.addProperty(new LambdaBooleanProperty(getMessage("gebiet.uebernehmen.gebiete.loeschen"), true, true, getEntity()::setRollenUebernehmen,
        getEntity()::isRollenUebernehmen));

    formBuilder.addProperty(new LambdaBooleanProperty(getMessage("gebiet.uebernehmen.gebiete.rollen.uebernehmen"), false, true, getEntity()::setUeberzaehligeGebieteLoeschen,
        getEntity()::isUeberzaehligeGebieteLoeschen));

    formBuilder.addProperty(new LambdaBooleanProperty(getMessage("gebiet.uebernehmen.gebiete.externe.id.erfassungsgebiete.uebernehmen"), false, true, getEntity()::setExterneIdFuerErfassungsgebieteUebernehmen,
        getEntity()::isExterneIdFuerErfassungsgebieteUebernehmen));

    formBuilder.addProperty(new LambdaBooleanProperty(getMessage("gebiet.uebernehmen.gebiete.anzahlen.sitze.stimmen.uebernehmen"), false, true, getEntity()::setAnzahlenSitzeStimmenUebernehmen,
        getEntity()::isAnzahlenSitzeStimmenUebernehmen));
  }

  private String getNameFuerGebietsart(Gebietsart gebietsart) {
    return defaultIfBlank(gebietsart.getTitel(), gebietsart.getName());
  }

  @Override
  public boolean isBtnSaveRendered() {
    return hasPermission(UseCasePermission.GEBIET_UEBERNEHMEN);
  }

  @Override
  @Redirect
  public String save() {
    GebietUebernehmenResult result = gebietUebernehmen.save(getEntity());

    if (result.equals(GebietUebernehmenResult.NICHTS_UEBRNOMMEN)) {
      addWarningMessage("gebiet.uebernehmen.nichts.uebernommen");
    }

    if (!result.getAnzahlNichtUebernommenerGebiete().isEmpty()) {
      addWarningMessage("gebiet.uebernehmen.gebietsarten.nicht.uebernommen", getGebietsartenTexte(result.getAnzahlNichtUebernommenerGebiete()));
    }

    if (!result.getAnzahlUebernommenerGebiete().isEmpty()) {
      addInfoMessage("gebiet.uebernehmen.gebietsarten.uebernommen", getGebietsartenTexte(result.getAnzahlUebernommenerGebiete()));
    }

    if (!result.getAnzahlBereitsVorhandenerGebiete().isEmpty()) {
      addInfoMessage("gebiet.uebernehmen.gebietsarten.bereits.vorhanden", getGebietsartenTexte(result.getAnzahlBereitsVorhandenerGebiete()));
    }

    if (!result.getAnzahlAktualisierterGebiete().isEmpty()) {
      addWarningMessage("gebiet.uebernehmen.gebietsarten.aktualisiert", getGebietsartenTexte(result.getAnzahlAktualisierterGebiete()));
    }

    if (!result.getAnzahlGeloeschterGebiete().isEmpty()) {
      addWarningMessage("gebiet.uebernehmen.gebietsarten.geloescht", getGebietsartenTexte(result.getAnzahlGeloeschterGebiete()));
    }

    gebietsbaumView.reset();

    if (!isGebietSelected()) {
      gebietSessionSelect.setEntity(result.getWurzelgebiet());
    }

    if (result.getAnzahlUebernommenerGebiete().isEmpty() && result.getAnzahlAktualisierterGebiete().isEmpty()) {
      return VIEW_ID;
    }

    return goBack(PARENT_VIEW_ID);
  }

  private String getGebietsartenTexte(Map<Gebietsart, Long> anzahlNachArt) {
    return anzahlNachArt.entrySet().stream().sorted(Comparator.comparing(u -> u.getKey().getPosition()))
        .map(e -> getNameFuerGebietsart(e.getKey()) + " (" + getMessage(GebietConstants.MESSAGE_KEY_ENTITY_MEHRZAHL) + ": " + e.getValue() + ")").collect(Collectors.joining(", "));
  }

  @Override
  public boolean isBtnResetRendered() {
    return true;
  }

  @Nullable
  @Override
  @Redirect
  public String reset() {
    init();

    return VIEW_ID;
  }

  @Override
  public boolean isBtnCancelRendered() {
    return true;
  }

  @Override
  @Redirect
  public String cancel() {
    return goBack(PARENT_VIEW_ID);
  }
}
