package de.ivu.elect.presentation.wahl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import de.ivu.elect.business.protokollierung.entity.LoeschProtokollEvent;
import de.ivu.elect.business.wahl.boundary.WahlExtendedDAO;
import de.ivu.elect.business.wahl.boundary.WahlResetAsync;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlPK;
import de.ivu.elect.business.wahl.entity.WahlResetStatusContainer;
import de.ivu.elect.business.wahl.entity.WahlResetStatusEntry;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.faces.UserLocale;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.MessageProperty;
import de.ivu.elect.jee.presentation.dynamicform.ReadOnlyStringProperty;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.AbstractElectCreateView;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.replikation.ReplikationPresentationStatus;


import static de.ivu.elect.business.security.UseCasePermission.WAHL_RESET;

/**
 *  on 07.06.2017.
 */
@OnlineHilfeId(value = "697")
@RequestScoped
@Named(WahlResetView.COMPONENT_NAME)
@View(viewId = WahlResetView.VIEW_ID, useCase = WAHL_RESET)
public class WahlResetView extends AbstractElectCreateView<Wahl> {

  public static final String COMPONENT_NAME = "wahlResetView";

  public static final String VIEW_ID = "/wahl/wahl-reset.xhtml";
  public static final int TIMEOUT_IN_MS = 200;

  private static final long serialVersionUID = 1L;

  @Inject
  private transient UserLocale userLocale;

  @EJB
  private transient WahlResetAsync wahlResetAsync;

  @Inject
  private transient ReplikationPresentationStatus replikationPresentationStatus;

  @Inject
  private transient LoeschProtokollEvent loeschProtokollEvent;

  @Inject
  private transient WahlExtendedDAO wahlExtendedDAO;

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

    return null;
  }

  @Override
  protected Wahl getEntity() {
    return getSelectedWahl();
  }

  @Override
  protected void addProperties(FormBuilder formBuilder, Wahl entity) {

    List<Wahl> aufgeteilteWahlen = getAufgeteilteWahlen();
    if (!aufgeteilteWahlen.isEmpty()) {
      formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("wahl.reset.aufgeteilte.wahlen"),
          aufgeteilteWahlen.stream().sorted(Comparator.comparing(u -> u.getMandant().getNummer())).map(w -> getMessage("wahl.reset.aufgeteilte.wahlen.mandant",
              w.getMandant().getNummer(),
              w.getMandant().getName())).collect(Collectors.joining(", "))));
    }

    WahlResetStatusContainer statusContainer = getStatusWahlRest(getSelectedWahl().getPk());
    for (WahlResetStatusEntry wahlResetStatusEntry : statusContainer.getEntries()) {
      formBuilder.addProperty(new ReadOnlyStringProperty(userLocale.formatTime(wahlResetStatusEntry.getTimestamp()),
          getMessage(wahlResetStatusEntry.getMsgKey(), (Object[]) wahlResetStatusEntry.getParams())));
    }
    formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("wahl.reset.status"), getMessage(statusContainer.getStatus())));

    for (Wahl aufgeteilteWahl : aufgeteilteWahlen) {
      WahlResetStatusContainer augeteiltStatus = getStatusWahlRest(aufgeteilteWahl.getPk());
      formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("wahl.reset.status.aufgeteilte.wahlen.mandant", aufgeteilteWahl.getMandant().getNummer(),
          aufgeteilteWahl.getMandant().getName()), getMessage(augeteiltStatus.getStatus())));

    }

    if (isBerichtetAnWahl()) {
      formBuilder.addProperty(new MessageProperty(getMessage("wahl.reset.nicht.moeglich.bereichtet.an", getSelectedWahl().getBerichtetAn().getMandant().getNummer(),
          getSelectedWahl().getBerichtetAn().getMandant().getName())));
    }
  }

  private List<Wahl> getAufgeteilteWahlen() {
    return wahlExtendedDAO.findByBerichtetAn(getSelectedWahl());
  }

  private transient WahlResetStatusContainer wahlResetStatusContainer;

  private WahlResetStatusContainer getStatusWahlRest(WahlPK pk) {
    if (wahlResetStatusContainer == null) {
      wahlResetStatusContainer = wahlResetAsync.getStatus(pk);
    }
    return wahlResetStatusContainer;
  }

  @Nullable
  @Override
  @Redirect
  public String reset() {
    loeschProtokollEvent.sendeLoeschProtokollEvent(getEntity(), getEntity(), "loesch.protokoll.wahl.reset", getEntity().getName(),
        userLocale.formatDate(getEntity().getWahldatum()));

    List<WahlPK> pks = new ArrayList<>();
    pks.add(getEntity().getPk());
    pks.addAll(getAufgeteilteWahlen().stream().map(Wahl::getPk).collect(Collectors.toList()));
    wahlResetAsync.reset(pks);

    try {
      TimeUnit.MILLISECONDS.sleep(TIMEOUT_IN_MS); // kurz warten, bis asynchrone Ausführung "hoffentlich" gestartet ist
    } catch (InterruptedException e) {
      // ignore
    }
    addInfoMessage("wahl.reset.gestartet");
    return VIEW_ID;
  }

  public boolean isBtnResetCustomRendered() {
    return isWahlSelected() && hasPermission(WAHL_RESET) && !isResetLaeuft() && !isSlave() && !isBerichtetAnWahl();
  }

  private boolean isBerichtetAnWahl() {
    Wahl selectedWahl = getSelectedWahl();
    return selectedWahl != null && selectedWahl.getBerichtetAn() != null;
  }

  // WASDE-1153
  private boolean isSlave() {
    return replikationPresentationStatus.isSlave();
  }

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

  @Override
  public String cancel() {
    return null;
  }

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

  @Override
  public boolean isBtnSaveRendered() {
    return false;
  }

  @Override
  public String save() {
    return null;
  }

  public boolean isResetLaeuft() {
    return getStatusWahlRest(getEntity().getPk()).getStatus().isZurueckSetzenLaeuftGerade();
  }
}




