
package de.ivu.elect.presentation.praesentation;

import de.ivu.elect.business.ergebnis.boundary.ErgebnisNichtAusgewaehltException;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisSessionSelect;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Praesentationsexportart;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.internet.boundary.*;
import de.ivu.elect.business.internet.control.PresentationGenerieren;
import de.ivu.elect.business.internet.entity.InternetSeite;
import de.ivu.elect.business.internet.entity.PraesentationKonfiguration;
import de.ivu.elect.business.internet.entity.Praesentationsexport;
import de.ivu.elect.business.praesentation.boundary.PraesentationStatistikStore;
import de.ivu.elect.business.praesentation.boundary.PraesentationStatusHelper;
import de.ivu.elect.business.praesentation.entity.PraesentationAutomatischenExportAnstossen;
import de.ivu.elect.business.praesentation.entity.PraesentationBereitstellen;
import de.ivu.elect.business.praesentation.entity.PraesentationErfassungsgebieteZurueckhalten;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.security.control.ElectCommonPrincipal;
import de.ivu.elect.business.wahl.boundary.WahldurchfuehrungSessionSelect;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.jee.faces.FacesContextUtil;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.faces.UserLocale;
import de.ivu.elect.jee.presentation.charts.AbstractChartModelBuilder;
import de.ivu.elect.jee.presentation.dynamicform.*;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.AbstractElectView;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.internet.InternetSeiteSearchView;
import de.ivu.elect.presentation.praesentation.menu.PraesentationGenerierenMenuItemEntry;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.model.chart.AxisType;
import org.primefaces.model.chart.CategoryAxis;
import org.primefaces.model.chart.LineChartModel;
import org.primefaces.model.chart.LineChartSeries;

import javax.annotation.Nullable;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Collections;
import java.util.List;

import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.*;
import static java.util.Arrays.asList;

@OnlineHilfeId("494")
@RequestScoped
@Named(PraesentationStatusView.COMPONENT_NAME)
@View(viewId = PraesentationStatusView.VIEW_ID, useCase = UseCasePermission.PRAESENTATION_STATUSUEBERSICHT_ANZEIGEN)
public class PraesentationStatusView extends AbstractElectView implements DynamicFormEditOrCreateView {

  private static final long serialVersionUID = 1L;

  public static final String VIEW_ID = "/praesentation/praesentation-status.xhtml";

  public static final String COMPONENT_NAME = "praesentationStatusView";

  @Inject
  private transient ErgebnisSessionSelect ergebnisSessionSelect;

  @Inject
  private transient ElectCommonPrincipal principal;

  @Inject
  private transient PraesentationStatistikStore statistikStore;

  @Inject
  private transient PraesentationsexportExtendedDAO praesentationsexportExtendedDAO;

  @Inject
  private transient WahldurchfuehrungSessionSelect wahldurchfuehrungSessionSelect;

  @Inject
  private transient PraesentationExportieren praesentationExportieren;

  @Inject
  private transient PraesentationKonfigurieren praesentationKonfigurieren;

  @Inject
  private transient PraesentationUrl praesentationUrl;

  @Inject
  private transient InternetSeiteExtendedDAO internetSeiteExtendedDAO;

  @Inject
  private transient Messages messages;

  @Inject
  private transient UserLocale userLocale;

  @Inject
  private transient PraesentationUploadServiceBoundary praesentationUploadServiceBoundary;

  @Inject
  private transient InternetPraesentationErmittler internetPraesentationErmittler;

  @Inject
  private transient PraesentationStatusHelper praesentationStatusHelper;

  @Inject
  private transient PraesentationGenerierenMenuItemEntry praesentationGenerierenMenuItemEntry;

  private transient Praesentationsexport praesentationsexport;

  public PraesentationStatusView() {
    super();
  }

  @Nullable
  @PreConditionCheck
  public String checkErgebnisSelected() {
    if (!ergebnisSessionSelect.isSelected()) {
      throw new ErgebnisNichtAusgewaehltException();
    }

    return null;
  }

  public Wahldurchfuehrung getWahl() {
    return wahldurchfuehrungSessionSelect.getEntity();
  }

  public Ergebnis getErgebnis() {
    return ergebnisSessionSelect.getEntity();
  }

  private AdvancedDynaFormModel model;

  @Override
  public AdvancedDynaFormModel getModel() {
    if (model == null) {
      var formBuilder = new FormBuilder();

      formBuilder.addSeparator("presentation.status.generierung");

      formBuilder.addProperty(
          new ReadOnlyBooleanProperty(getMessage("presentation.generierung.laeuft.gerade"), PresentationGenerieren.laeuftGenerierung(getWahl().getPk())));

      formBuilder.addSeparator("presentation.konfigurieren.system.parameter");
      var praesentationKonfiguration = getPraesentationKonfiguration();
      var internetAktiviertProperty = praesentationKonfiguration.getInternetAktiviertProperty(getMessages());
      formBuilder.addProperty(internetAktiviertProperty).withLabel(getMessage("praesentation.status.automatisch.exportieren")).readonly();

      formBuilder.addProperty(new ReadOnlyBooleanProperty(getMessage("praesentation.status.ausgabeverzeichnis.konfiguriert"),
          praesentationExportieren.isVerzeichnisKonfiguriert(getMandant())));

      formBuilder.addSeparator("praesentation.status.einstellungen");
      formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("praesentation.status.diese.wahl.exportieren"),
          getMessage(praesentationKonfiguration.getPraesentationBereitstellen())));

      if (isEinstellungVerhindertPraesentation(praesentationKonfiguration.getPraesentationBereitstellen())) {
        formBuilder.withInfoMessage(getMessage("praesentation.status.diese.wahl.exportieren.verhindert"));
      }

      formBuilder
          .addProperty(new LambdaEnumProperty<>(messages.lokalisiere(PREASENTATIION_AUTOMATISCHEN_EXPORT_ANSTOSSEN), true,
              praesentationKonfiguration::setPraesentationAutomatischenExportAnstossen,
              praesentationKonfiguration::getPraesentationAutomatischenExportAnstossen, PraesentationAutomatischenExportAnstossen.class,
              asList(PraesentationAutomatischenExportAnstossen.values())))
          .readonly();

      formBuilder.addProperty(new LambdaLongProperty(messages.lokalisiere(PREASENTATIION_ERFASSUNGSGEBIETE_PRO_WAHLGEBIET_NOTWENDIG), false,
          praesentationKonfiguration::setPraesentationErfassungsgebieteNotwendig, praesentationKonfiguration::getPraesentationErfassungsgebieteNotwendig, 0L,
          100L)).readonly();

      formBuilder.addProperty(new LambdaEnumProperty<>(messages.lokalisiere(PREASENTATIION_ERFASSUNGSGEBIETE_ZURUECKHALTEN), true,
          this.praesentationKonfiguration::setPraesentationErfassungsgebieteZurueckhalten,
          this.praesentationKonfiguration::getPraesentationErfassungsgebieteZurueckhalten,
          PraesentationErfassungsgebieteZurueckhalten.class, asList(PraesentationErfassungsgebieteZurueckhalten.values()))).readonly();

      // formBuilder.addProperty(getPraesentationKonfiguration().getWahldurchfuehrung().getProperties().getPraesentationUrlProperty()).readonly();

      formBuilder.addSeparator("presentation.konfigurieren.url.seprator");

      formBuilder.addProperty(
          new ReadOnlyStringProperty(getMessage("presentation.konfigurieren.url.vollstaendig"), praesentationUrl.getPraesentationIndexUrl()));


      formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("praesentation.url.label"), praesentationUrl.getPraesentationIndexUrlExtern()));

      formBuilder.addSeparator("praesentation.status.internet.seiten");

      var internetSeitenInWahlVorhanden = praesentationStatusHelper.isInternetSeitenInWahlVorhanden(getWahl());
      formBuilder.addProperty(new ReadOnlyBooleanProperty(getMessage("praesentation.status.internet.seiten.manuelle.seiten"), internetSeitenInWahlVorhanden));

      if (!praesentationExportieren.isMapperVorhanden(getErgebnis().getPk())) {
        formBuilder.withInfoMessage(getMessage("praesentation.status.internet.seiten.fehlen"));
      }
      var internetSeitenInDokumentvorlageVorhanden = praesentationStatusHelper.isInternetSeitenInDokumentvorlageVorhanden(getWahl());
      formBuilder.addProperty(
          new ReadOnlyBooleanProperty(getMessage("praesentation.status.internet.seiten.dokumentvorlage.vorhanden"), internetSeitenInDokumentvorlageVorhanden));
      formBuilder.addProperty(new ReadOnlyBooleanProperty(getMessage("praesentation.status.internet.seiten.dokumentvorlage.verwenden"),
          !internetSeitenInWahlVorhanden && internetSeitenInDokumentvorlageVorhanden && praesentationStatusHelper.isDokumentvorlageVerwenden(getWahl())));

      var praesentationsexport = getPraesentationsexport();

      if (praesentationsexport == null) {
        formBuilder.addSeparator("praesentation.status.kein.export");
      } else {
        formBuilder.addSeparator("praesentation.status.letzter.export");

        var properties = praesentationsexport.getProperties();

        formBuilder.addProperty(praesentationsexport.getDatei().getProperties().getErstellungszeitpunktProperty()).readonly();
        //      formBuilder.addProperty(properties.getPraesentationsexportartProperty()).readonly();
        //    formBuilder.addProperty(properties.getStimmabgabeartProperty()).readonly();
        formBuilder.addProperty(properties.getLetzteEingangssequenznummerProperty()).readonly();
        //  formBuilder.addProperty(properties.getExportsequenznummerProperty()).readonly();
        // stimmt nicht mehr... formBuilder.addProperty(properties.getPraesentationsexportausloeserProperty()).readonly();
      }

      formBuilder.addSeparator("praesentation.status.upload.service");

      var praesentationUploadServiceTyp = praesentationUploadServiceBoundary.getPraesentationUploadServiceTyp(getWahl());
      formBuilder.addProperty(
          new ReadOnlyStringProperty(messages.lokalisiere(PREASENTATIION_UPLOAD_SERVICE_TYP), messages.lokalisiere(praesentationUploadServiceTyp)));

      if ((FacesContextUtil.isAjaxRequest() || !FacesContext.getCurrentInstance().isPostback() /* Verbindungsstatus Status nicht beim POST abfragen */)
          && praesentationUploadServiceTyp.isVorhanden()) {

        var praesentationUploadServiceStatus = praesentationUploadServiceBoundary.getPraesentationUploadServiceStatus(getWahl());

        var statusProperty = new ReadOnlyStringProperty(messages.lokalisiere(PREASENTATIION_UPLOAD_SERVICE_STATUS),
            praesentationUploadServiceStatus.getColor());
        statusProperty.setTooltip(messages.lokalisiere(praesentationUploadServiceStatus));
        formBuilder.addProperty(statusProperty).withType(PropertyType.INPUT_COLOR);

        var uploadServiceAvailable = praesentationUploadServiceBoundary.isUploadServiceAvailable(getWahl());

        var verbindungProperty = new ReadOnlyStringProperty(getMessage("praesentation.status.upload.service.status.verbindung"),
            getCronColor(uploadServiceAvailable.isEmpty()));
        verbindungProperty.setTooltip(getMessage("praesentation.status.upload.service.status.verbindung." + uploadServiceAvailable.isEmpty()));

        formBuilder.addProperty(verbindungProperty).withType(PropertyType.INPUT_COLOR);

        if (!uploadServiceAvailable.isEmpty()) {
          formBuilder.addSeparator("praesentation.status.upload.service.fehlermeldung");
          for (var fehler : uploadServiceAvailable) {
            formBuilder.addProperty(new ReadOnlyStringProperty(getMessage("praesentation.status.upload.service.fehler"), fehler));
          }
        }
      }
      model = formBuilder.createModel();
    }

    return model;
  }

  private boolean isEinstellungVerhindertPraesentation(PraesentationBereitstellen praesentationBereitstellen) {
    if (praesentationBereitstellen == null) {
      return false;
    }

    return !praesentationBereitstellen.isAktiviert(getErgebnis().getErgebnisart(), this::isOberstesGebietFreigegeben);

  }

  private boolean isOberstesGebietFreigegeben() {
    var oberstesGebiet = findeOberstesGebiet(getSelectedGebiet());
    if (oberstesGebiet == null) {
      return false;
    }

    return oberstesGebiet.isFreigegebenOderUebergeordnetesGebietFreigegeben(getErgebnis());
  }

  @Nullable
  private Wahldurchfuehrungsgebiet findeOberstesGebiet(Gebiet selectedGebiet) {
    if (selectedGebiet == null) {
      return null;
    }

    if (selectedGebiet.hasUebergeordnetesGebiet()) {
      return findeOberstesGebiet(selectedGebiet.getUebergeordnetesGebiet());
    }
    return selectedGebiet.castTo(Wahldurchfuehrungsgebiet.class).getEntity();
  }

  private String getCronColor(boolean aktiv) {
    var cronStatusColor = AbstractChartModelBuilder.ROT;
    if (aktiv) {
      cronStatusColor = AbstractChartModelBuilder.GRUEN;
    }
    return cronStatusColor;
  }

  @Nullable
  protected Praesentationsexport getPraesentationsexport() {
    if (praesentationsexport == null) {
      var result = praesentationsexportExtendedDAO.findByErgebnisAndArten(getErgebnis(), Praesentationsexportart.INTERNET,
          Stimmabgabeart.GESAMT);
      if (result.isEmpty()) {
        return null;
      }

      result.sort((u, v) -> v.getLetzteEingangssequenznummer().compareTo(u.getLetzteEingangssequenznummer()));

      praesentationsexport = result.get(0);
      praesentationsexport.getDatei().getErstellungszeitpunkt(); // eager loading...

    }

    return praesentationsexport;
  }

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

  @Override
  public String getBtnSaveLabel() {
    return getMessage("entity.edit.action.save");
  }

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

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

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

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

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

  private LineChartModel praesentationDauerLineChartModel;

  private boolean praesentationDauerLineChartRendered = false;

  public boolean isPraesentationDauerLineChartRendered() {
    getPraesentationDauerLineChartModel(); // baue Modell wenn noch nicht erfolgt
    return praesentationDauerLineChartRendered;
  }

  public LineChartModel getPraesentationDauerLineChartModel() {
    if (praesentationDauerLineChartModel == null) {
      praesentationDauerLineChartModel = erzeugeErgebnisDauerLineChartModel();
    }
    return praesentationDauerLineChartModel;
  }

  private LineChartModel erzeugeErgebnisDauerLineChartModel() {
    var dauerGesamtSeries = new LineChartSeries();
    dauerGesamtSeries.setLabel(messages.getMessageForMessageKey("praesentation.status.series.dauer.gesamt"));

    var dauerLadenSeries = new LineChartSeries();
    dauerLadenSeries.setLabel(messages.getMessageForMessageKey("praesentation.status.series.dauer.laden"));

    var dauerContextSeries = new LineChartSeries();
    dauerContextSeries.setLabel(messages.getMessageForMessageKey("praesentation.status.series.dauer.kontext"));

    var dauerRendernSeries = new LineChartSeries();
    dauerRendernSeries.setLabel(messages.getMessageForMessageKey("praesentation.status.series.dauer.rendern"));

    var dauerUploadSeries = new LineChartSeries();
    dauerUploadSeries.setLabel(messages.getMessageForMessageKey("praesentation.status.series.dauer.upload"));

    var lineChartModel = new LineChartModel();
    lineChartModel.addSeries(dauerGesamtSeries);
    lineChartModel.addSeries(dauerUploadSeries);
    lineChartModel.addSeries(dauerRendernSeries);
    lineChartModel.addSeries(dauerLadenSeries);
    lineChartModel.addSeries(dauerContextSeries);

    lineChartModel.setLegendPosition("ne");
    lineChartModel.getAxes().put(AxisType.X, new CategoryAxis(messages.getMessageForMessageKey("praesentation.status.axis.time")));
    lineChartModel.getAxis(AxisType.X).setTickAngle(270);
    lineChartModel.getAxis(AxisType.Y).setMin(0);
    lineChartModel.getAxis(AxisType.Y).setLabel(messages.getMessageForMessageKey("praesentation.status.axis.milliseconds"));
    lineChartModel.setZoom(false);

    for (var statistikEntry : statistikStore.getStatistikFuerErgebnis(getErgebnis().getPk())) {
      praesentationDauerLineChartRendered = true;

      var timeFormatted = userLocale.formatTime(statistikEntry.getZeitpunkt());

      dauerGesamtSeries.set(timeFormatted, statistikEntry.getDauerInMs());
      dauerLadenSeries.set(timeFormatted, statistikEntry.getDauerLaden());
      dauerContextSeries.set(timeFormatted, statistikEntry.getDauerContext());
      dauerRendernSeries.set(timeFormatted, statistikEntry.getDauerRendern());
      dauerUploadSeries.set(timeFormatted, statistikEntry.getDauerUpload());
    }

    return lineChartModel;
  }

  public PraesentationKonfiguration getPraesentationKonfiguration() {
    if (praesentationKonfiguration == null) {
      praesentationKonfiguration = praesentationKonfigurieren.getPraesentationKonfiguration(wahldurchfuehrungSessionSelect.getEntity());
    }
    return praesentationKonfiguration;
  }

  private PraesentationKonfiguration praesentationKonfiguration;

  public boolean isBtnPraesentationVeroeffentlichenRendered() {
    return praesentationGenerierenMenuItemEntry.isRendered();
  }

  public boolean isBtnPraesentationVeroeffentlichenDisabled() {
    return praesentationGenerierenMenuItemEntry.isDisabled();
  }

  public boolean isBtnConfigUploadServiceRendered() {
    return principal.hasUseCasePermission(UseCasePermission.PRAESENTATION_KONFIGURIEREN);
  }

  public boolean isBtnConfigUploadServiceDisabled() {
    return false;
  }

  @Redirect
  public String configUploadService() {
    return PraesentationUploadServiceKonfigurationView.VIEW_ID;
  }

  public boolean isBtnConfigRendered() {
    return principal.hasUseCasePermission(UseCasePermission.PRAESENTATION_KONFIGURIEREN);
  }

  public boolean isBtnConfigInternetSeitenRendered() {
    return principal.hasUseCasePermission(UseCasePermission.INTERNET_SEITE_SEARCH);
  }

  public boolean isBtnConfigDisabled() {
    return false;
  }

  public boolean isBtnConfigInternetSeitenDisabled() {
    return false;
  }

  @Redirect
  public String config() {
    return PraesentationKonfigurierenView.VIEW_ID;
  }

  @Redirect
  public String configInternetSeiten() {
    return InternetSeiteSearchView.VIEW_ID;
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.PRAESENTATION_EXPORTIEREN)
  public String erstellePraesentation() {
    praesentationExportieren.exportiereInternetPraesentation();
    return VIEW_ID;
  }

  public boolean isBtnPraesentationOeffnenRendered() {
    return principal.hasUseCasePermission(UseCasePermission.PRAESENTATION_OEFFNEN);
  }

  public boolean isBtnPraesentationOeffnenDisabled() {
    return getWahl() == null || StringUtils.isEmpty(praesentationUrl.getPraesentationIndexUrl()) || getPraesentationsexport() == null;
  }

  public List<InternetSeite> getInternetSeiten() {
    if (internetPraesentationErmittler.getInternetPraesentationTyp().isWidgetsKonfigurierbar()) {
      return internetSeiteExtendedDAO.findByWahl(getWahl());
    }
    return Collections.emptyList();
  }

}
