package de.ivu.elect.presentation.wahl;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.constraints.Null;

import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.mandant.boundary.MandantExtendedDAO;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.mandant.entity.MandantPK;
import de.ivu.elect.business.wahl.boundary.WahlMandantenAufteilen;
import de.ivu.elect.business.wahl.control.WahlMandantenAufteilenAsynchron;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlaufteilenResultContainer;
import de.ivu.elect.business.wahl.entity.WahlaufteilenStatusContainer;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.PropertyType;
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.gebietsbaum.GebietNummerFormatter;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.mandant.MandantNameFormatter;


import static de.ivu.elect.business.security.UseCasePermission.WAHL_FUER_SUBSYSTEME_KONFIGURIEREN;
import static de.ivu.elect.business.security.UseCasePermission.WAHL_FUER_SUBSYSTEME_LOESCHEN;
import static java.util.Collections.emptyMap;

@RequestScoped
@Named(WahlMandantenAufteilenView.COMPONENT_NAME)
@View(viewId = WahlMandantenAufteilenView.VIEW_ID, useCase = WAHL_FUER_SUBSYSTEME_KONFIGURIEREN)
@OnlineHilfeId("790")
public class WahlMandantenAufteilenView extends AbstractElectCreateView<Wahl> {

  public static final String COMPONENT_NAME = "wahlMandantenAufteilenView";

  public static final String VIEW_ID = "/wahl/wahl-mandanten-aufteilen.xhtml";

  private static final long serialVersionUID = 1L;

  @Inject
  private transient WahlMandantenAufteilenMoeglich wahlMandantenAufteilenMoeglich;

  @Inject
  private transient WahlMandantenAufteilen wahlMandantenAufteilen;

  @Inject
  private transient MandantExtendedDAO mandantExtendedDAO;

  @Inject
  private transient MandantNameFormatter mandantNameFormatter;

  @Inject
  private transient GebietNummerFormatter gebietNummerFormatter;

  @Inject
  private transient GebietExtendedDAO gebietExtendedDAO;

  @Nullable
  @PreConditionCheck
  public String checkCondition() {
    if (!wahlMandantenAufteilenMoeglich.isAufteilenMoeglich()) {
      return getStartViewId();
    }

    if (WahlMandantenAufteilenAsynchron.WAHLEN_AUFTEILEN_LAEUFT.get()) {
      addWarningMessage("mandant.aufteilen.laeuft.asynchron");
    }
    if (WahlMandantenAufteilenAsynchron.WAHLEN_LOESCHEN_LAEUFT.get()) {
      addWarningMessage("mandant.loeschen.laeuft.asynchron");
    }

    return null;
  }

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

  @Override
  protected void addProperties(FormBuilder formBuilder, Wahl entity) {
    Map<MandantPK, WahlaufteilenStatusContainer> mandantPKWahlaufteilenStatusContainerMap = getMandantenAufteilenStatus(entity);
    List<Mandant> mandanten = ladeMandanten(mandantPKWahlaufteilenStatusContainerMap.keySet());
    if (mandanten.isEmpty()) {
      formBuilder.addSeparator("mandant.aufteilen.kein.verantwortlicher.mandant.festgelegt");
    } else {
      for (Mandant mandant : mandanten) {
        formBuilder.addSeparator("mandant.aufteilen.separator", mandantNameFormatter.formatiereName(mandant));
        WahlaufteilenStatusContainer wahlaufteilenStatusContainer = mandantPKWahlaufteilenStatusContainerMap.get(mandant.getPk());


        ReadOnlyStringProperty statusProperty = new ReadOnlyStringProperty(messages.getMessageForMessageKey("mandant.aufteilen.status.icon"),
            wahlaufteilenStatusContainer.getWahlaufteilenStatus().getColor());
        statusProperty.setTooltip(getMessage(wahlaufteilenStatusContainer.getWahlaufteilenStatus()));
        formBuilder.addProperty(statusProperty).withType(PropertyType.INPUT_COLOR);


        formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("mandant.aufteilen.status.label"),
            getMessage(wahlaufteilenStatusContainer.getWahlaufteilenStatus())));

        for (GebietPK gebietPK : wahlaufteilenStatusContainer.getWurzelgebiete()) {
          formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("mandant.aufteilen.wurzelgebiet.label"),
              gebietNummerFormatter.getDarstellung(gebietExtendedDAO.findByPrimaryKey(gebietPK))));
        }

      }
    }
  }

  private transient Map<MandantPK, WahlaufteilenStatusContainer> mandantenAufteilenStatus = null;

  private Map<MandantPK, WahlaufteilenStatusContainer> getMandantenAufteilenStatus(Wahl entity) {
    if (entity == null) {
      return emptyMap();
    }
    if (mandantenAufteilenStatus == null) {
      mandantenAufteilenStatus = wahlMandantenAufteilen.bestimmeStatusFuerMandanten(entity);
    }
    return mandantenAufteilenStatus;
  }

  private void resetMandantenAufteilenStatus() {
    mandantenAufteilenStatus = null;
  }

  private List<Mandant> ladeMandanten(Set<MandantPK> mandantPKs) {
    return mandantPKs.stream().map(mandantPK -> mandantExtendedDAO.findByPrimaryKey(mandantPK))
        .sorted(Comparator.comparing(Mandant::getNummer)).collect(Collectors.toList());
  }

  @Override
  public boolean isBtnSaveRendered() {
    return !isHintergrungLaeuft() && isMandantFuerAufteilenVorhanden(getEntity());
  }


  private boolean isHintergrungLaeuft() {
    return WahlMandantenAufteilenAsynchron.WAHLEN_AUFTEILEN_LAEUFT.get() || WahlMandantenAufteilenAsynchron.WAHLEN_LOESCHEN_LAEUFT.get();
  }
  private boolean isMandantFuerAufteilenVorhanden(Wahl entity) {
    return getMandantenAufteilenStatus(entity).values().stream().anyMatch(c -> c.getWahlaufteilenStatus().isAufteilenMoeglich());
  }

  @Override
  @Redirect
  public String save() {
    resetMandantenAufteilenStatus();

    Map<MandantPK, WahlaufteilenResultContainer> result = wahlMandantenAufteilen.aufteilen(getEntity());
    if (result == null) {
      addWarningMessage("mandant.aufteilen.asynchron");
    } else {
      if (result.keySet().isEmpty()) {
        addWarningMessage("mandant.aufteilen.keine.wahl.erstellt");
      } else {
        for (Mandant mandant : ladeMandanten(result.keySet())) {
          WahlaufteilenResultContainer wahlaufteilenResultContainer = result.get(mandant.getPk());
          addInfoMessage("mandant.aufteilen.wahl.erstellt", mandantNameFormatter.formatiereName(mandant),
              wahlaufteilenResultContainer.getCustomDateiImportBericht().getBericht());
        }
      }
    }

    return VIEW_ID;
  }

  @Nullable
  @Override
  @Redirect
  public String reset() {
    resetMandantenAufteilenStatus();
    return null;
  }

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

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

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

  @Override
  public String getBtnSaveLabel() {
    return getMessage("mandant.aufteilen.wahl.aufteilen.label");
  }

  public boolean isBtnDeleteWahlenRendered() {
    return hasPermission(WAHL_FUER_SUBSYSTEME_LOESCHEN) && !isHintergrungLaeuft() && isMindestensEineWahlAufgeteilt();
  }

  @Redirect
  public String deleteWahlen(){
    wahlMandantenAufteilen.aufgeteilteWahlenLoeschen(getEntity());
    addWarningMessage("mandant.wahlen.loeschen.asynchron");
    return VIEW_ID;
  }

  private boolean isMindestensEineWahlAufgeteilt() {
    return getMandantenAufteilenStatus(getEntity()).values().stream().anyMatch(value -> value.getWahlaufteilenStatus().isWahlLoeschenMoeglich());
  }

}




