
package de.ivu.elect.presentation.wahl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.NoResultException;

import org.apache.deltaspike.core.api.scope.ConversationGroup;
import org.apache.deltaspike.core.api.scope.ViewAccessScoped;

import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.wahl.boundary.WahlartConversationStore;
import de.ivu.elect.business.wahl.boundary.WahlartSearch;
import de.ivu.elect.business.wahl.boundary.WahlartSearchParameters;
import de.ivu.elect.business.wahl.boundary.WahlterminExtendedDAO;
import de.ivu.elect.business.wahl.boundary.WahlterminFactory;
import de.ivu.elect.business.wahl.control.WahlUtils;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.jee.entity.EagerLoadingCollector;
import de.ivu.elect.jee.faces.FacesContextUtil;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.AbstractDateProperty;
import de.ivu.elect.jee.presentation.dynamicform.AbstractStringProperty;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.wahl.form.WahlViewFormBuilder;


import static java.util.Collections.emptySet;

@OnlineHilfeId("388")
@ViewAccessScoped // ELECT-9153
@Named(WahlCreateView.COMPONENT_NAME)
public class WahlCreateView extends AbstractWahlCreateView implements WahldatumWahlView {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient WahlterminExtendedDAO wahlterminDao;

  @Inject
  private transient WahlterminFactory wahlterminFactory;

  @Inject
  private transient WahlartSearch wahlartSearch;

  @Inject
  @ConversationGroup(WahlartConversationStore.class)
  // NOTE, dass dieser Zustand benötigt wird, um Eingabefelder (auch nach fehlgeschlagener Validierung) per auto-update ein- und auszublenden.
  protected transient WahlartConversationStore wahlartSelect;

  @Inject
  private transient WahlViewFormBuilder viewFormBuilder;

  @Inject
  private transient WahlCreateWahlartFilter wahlartFilter;

  private List<Wahlart> wahlarten;

  public WahlCreateView() {
    super();
  }

  @PreConditionCheck
  public String checkPreCondition() {
    if (getMandant() == null) { // Ansonsten NPE nach Neustart bei Verwendung als Start-View (bspw. in NL-WUS)...
      return cancel();
    }

    return null;
  }

  @Override
  @PostConstruct
  public void init() {
    super.init();

    initWahl(getEntity());
  }

  protected void initWahl(Wahl wahl) {
    wahl.setAnzahlUnterstuetzerPerEintragungsliste(0L); // Im WVZ kein sinnvoller default => 0
    setzeWahltermin(wahl);

    Wahlart wahlart = getSelectedWahlart();

    if (wahlart != null) {
      wahl.setWahlart(wahlart);
      wahl.setFarbe(wahlart.getFarbe());
    }
  }

  protected void setzeWahltermin(Wahl wahl) {
    Wahltermin wahltermin = wahlterminFactory.create();
    wahltermin.setMandant(getMandant());
    wahl.setWahltermin(wahltermin);
  }

  @Override
  @Redirect
  @UseCaseSecure(UseCasePermission.WAHL_CREATE)
  public String save() {
    Wahl wahl = getEntity();
    wahl.setWahlart(getSelectedWahlart());

    if (!preSave(wahl)) {
      return FacesContextUtil.getCurrentViewId();
    }

    String outcome = super.save();

    outcome = postSave(wahl, outcome);

    return outcome;
  }

  protected boolean preSave(Wahl wahl) {
    return true;
  }

  protected String postSave(Wahl wahl, String outcome) {
    checkQuorum(wahl);
    return outcome;
  }

  protected void checkQuorum(Wahl wahl) {
    // ELECT-8461
    if (wahl.getQuorumProzenthuerde() == null) {
      addWarningMessage("wahl.edit.quorum.prozenthuerde.nicht.gesetzt");
    }
  }

  @Override
  public void addProperties(FormBuilder formBuilder, Wahl wahl) {
    viewFormBuilder.addProperties(formBuilder, wahl, wahlartSelect, getWahlarten(), getWahlterminWahldatumProperty());
  }

  @Override
  public AbstractDateProperty getWahlterminWahldatumProperty() {
    return getEntity().getWahltermin().getProperties().getWahldatumProperty();
  }

  @Override
  public AbstractStringProperty getWahlterminWahlnummerProperty() {
    return getEntity().getWahltermin().getProperties().getNummerProperty();
  }

  @Override
  public List<FacesMessage> getWahlterminWahldatumHints() {
    List<FacesMessage> result = new ArrayList<>();

    Collection<Wahl> wahlenByWahlterminWahldatum = findWahlenByWahlterminWahldatum(getEntity().getWahltermin());

    if (!wahlenByWahlterminWahldatum.isEmpty()) {
      result.add(new FacesMessage(FacesMessage.SEVERITY_INFO, "",
          getMessage("wahl.wahltermin.not.unique.message", WahlUtils.getWahlartenAsString(wahlenByWahlterminWahldatum), getEntity().getWahldatum(), wahlenByWahlterminWahldatum.size())));
    }

    return result;
  }

  protected Collection<Wahl> findWahlenByWahlterminWahldatum(Wahltermin wahltermin) {
    if (wahltermin.getWahldatum() != null) {
      try {
        return wahlterminDao.findByUK(wahltermin.getWahlterminUK()).getWahlsByWahltermin();
      } catch (NoResultException expected) {
        // ignorieren
      }
    }

    return emptySet();
  }

  @Override
  protected void resetStateAfterAction() {
    super.resetStateAfterAction();

    wahlartSelect.close();
  }

  private boolean isWahlartSelected() {
    return wahlartSelect.isSelected();
  }

  private Wahlart getSelectedWahlart() {
    return wahlartSelect.getEntity();
  }

  protected List<Wahlart> getWahlarten() {
    if (wahlarten == null) {
      WahlartSearchParameters wahlartSearchParameters = new WahlartSearchParameters();
      wahlartSearchParameters.setMandant(getMandant());
      wahlartSearchParameters.setSystemGebietsebeneAkzeptiert(getMandant().getSystemGebietsebene());

      wahlarten = wahlartFilter.filter(wahlartSearch.getSearchResult(wahlartSearchParameters, EagerLoadingCollector.<Wahlart> create()));
    }

    return wahlarten;
  }

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

  @Override
  public boolean isWahlnummerRendered() {
    return isWahldatumRendered();
  }
}
