
package de.ivu.elect.presentation.niederschrift;

import static java.util.Arrays.asList;
import static java.util.Objects.nonNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.model.chart.PieChartModel;

import de.ivu.elect.business.gebietsbaum.boundary.GebietSelectChangeEvent;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftStatusuebersicht;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftStatusuebersichtViewAccessStore;
import de.ivu.elect.business.niederschrift.entity.Niederschrift;
import de.ivu.elect.business.niederschrift.entity.NiederschriftArt;
import de.ivu.elect.business.niederschrift.entity.NiederschriftConstants;
import de.ivu.elect.business.niederschrift.entity.NiederschriftStatus;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.charts.AbstractChartModelBuilder;
import de.ivu.elect.jee.presentation.charts.PieChartModelBuilder;
import de.ivu.elect.presentation.AbstractElectStatusuebersichtView;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;

@OnlineHilfeId("276") // TODO ELECTMUC-2813 eigene Hilfeseite erstellen
@RequestScoped
@Named(NiederschriftStatusuebersichtView.COMPONENT_NAME)
@View(viewId = NiederschriftStatusuebersichtView.VIEW_ID, useCase = UseCasePermission.NIEDERSCHRIFT_STATUSUEBERSICHT_ANZEIGEN)
public class NiederschriftStatusuebersichtView extends AbstractElectStatusuebersichtView<Niederschrift> {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "niederschriftStatusuebersichtView";

  public static final String VIEW_ID = "/niederschrift/niederschrift-statusuebersicht.xhtml";

  private static final List<NiederschriftArt> NIEDERSCHRIFT_ARTEN_BETRACHTET = asList(NiederschriftArt.NIEDERSCHRIFT,
      NiederschriftArt.SCHNELLMELDUNG, NiederschriftArt.VERHANDLUNGSTASCHE);

  @Inject
  private transient NiederschriftStatusuebersicht niederschriftStatusuebersicht;

  @Inject
  private transient NiederschriftStatusuebersichtViewAccessStore niederschriftStatusuebersichtViewAccessStore;

  private PieChartModel pieChartModelSchnellmeldungen;

  private PieChartModel pieChartModelVerhandlungstaschen;

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

  public String getPageTitle() {
    return getMessage("entity.status.page.title", getMessage(NiederschriftConstants.MESSAGE_KEY_ENTITY_MEHRZAHL));
  }

  public String getPageHeader() {
    String msgEntityMehrzahl = getMessage(NiederschriftConstants.MESSAGE_KEY_ENTITY_MEHRZAHL);

    if (isGebietSelected()) {
      return getMessage("entity.mit.gebiet.status.page.header", msgEntityMehrzahl, getSelectedGebietNameFormatted());
    }

    return getMessage("entity.status.page.header", msgEntityMehrzahl);
  }

  @Override
  public String save() {
    niederschriftStatusuebersichtViewAccessStore.reset();
    return super.save();
  }

  @Override
  public void onGebietSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) GebietSelectChangeEvent event) {
    niederschriftStatusuebersichtViewAccessStore.reset();
    super.onGebietSelectChangeEvent(event);
  }

  public PieChartModel getPieChartModelSchnellmeldungen() {
    if (pieChartModelSchnellmeldungen == null) {
      PieChartModelBuilder modelBuilder = createPieChartModelBuilder();
      fillPieChartModel(modelBuilder, NiederschriftArt.SCHNELLMELDUNG);
      pieChartModelSchnellmeldungen = modelBuilder.buildModel();
    }
    return pieChartModelSchnellmeldungen;
  }

  public PieChartModel getPieChartModelVerhandlungstaschen() {
    if (pieChartModelVerhandlungstaschen == null) {
      PieChartModelBuilder modelBuilder = createPieChartModelBuilder();
      fillPieChartModel(modelBuilder, NiederschriftArt.VERHANDLUNGSTASCHE);
      pieChartModelVerhandlungstaschen = modelBuilder.buildModel();
    }
    return pieChartModelVerhandlungstaschen;
  }

  @Override
  protected void fillStatusPieChartModel(PieChartModelBuilder modelBuilder) {
    fillPieChartModel(modelBuilder, NiederschriftArt.NIEDERSCHRIFT);
  }

  private void fillPieChartModel(PieChartModelBuilder modelBuilder, NiederschriftArt niederschriftArt) {
    Map<NiederschriftStatus, Map<String, Long>> anzahlPerNiederschriftStatus = getAnzahlPerNiederschriftStatus()
        .get(niederschriftArt);

    if (anzahlPerNiederschriftStatus == null) {
      throw new UnsupportedOperationException(String.format(
          "Für die NiederschriftArt '{0}' wurden keine Werte ermittelt, siehe getAnzahlPerNiederschriftStatus().",
          niederschriftArt.name()));
    }

    addEntryFuerStatusUnbekannt(modelBuilder, anzahlPerNiederschriftStatus);

    for (NiederschriftStatus niederschriftStatus : NiederschriftStatus.getValuesNichtDeprecated()) {
      addEntryFuerStatus(modelBuilder, anzahlPerNiederschriftStatus, niederschriftStatus);
    }
  }

  private Map<NiederschriftArt, Map<NiederschriftStatus, Map<String, Long>>> getAnzahlPerNiederschriftStatus() {
    if (!niederschriftStatusuebersichtViewAccessStore.isAnzahlPerNiederschriftStatusSelected()) {
      niederschriftStatusuebersichtViewAccessStore.setAnzahlPerNiederschriftStatus(niederschriftStatusuebersicht
          .getAnzahlPerNiederschriftStatus(NIEDERSCHRIFT_ARTEN_BETRACHTET, getSelectedWahldurchfuehrungsgebiet()));
    }
    return niederschriftStatusuebersichtViewAccessStore.getAnzahlPerNiederschriftStatus();
  }

  private Wahldurchfuehrungsgebiet getSelectedWahldurchfuehrungsgebiet() {
    if (isGebietSelected()) {
      return getSelectedGebiet().castTo(Wahldurchfuehrungsgebiet.class).getEntity();
    }
    return null;
  }

  private void addEntryFuerStatusUnbekannt(PieChartModelBuilder modelBuilder,
      Map<NiederschriftStatus, Map<String, Long>> anzahlPerNiederschriftStatus) {

    Long chartEntrySummeUnbekannt = 0L;
    Map<String, Long> unbekanntMap = anzahlPerNiederschriftStatus.get(null);
    if (nonNull(unbekanntMap)) {
      chartEntrySummeUnbekannt = unbekanntMap.get(null);
    }

    modelBuilder.add(getMessage("niederschrift.statusuebersicht.entry.label",
        getMessage("NiederschriftStatus.UNBEKANNT"), chartEntrySummeUnbekannt), chartEntrySummeUnbekannt,
        AbstractChartModelBuilder.HELL_GRAU);
  }

  private void addEntryFuerStatus(PieChartModelBuilder modelBuilder,
      Map<NiederschriftStatus, Map<String, Long>> anzahlPerNiederschriftStatus,
      NiederschriftStatus niederschriftStatus) {

    Map<String, Long> anzahlProRaum = anzahlPerNiederschriftStatus.get(niederschriftStatus);

    Long chartEntrySumme = 0L;
    List<String> chartEntryLabelAnzahlenAnteiligFormatted = new ArrayList<>();

    if (nonNull(anzahlProRaum)) {
      chartEntrySumme = anzahlProRaum.values().stream().mapToLong(Long::longValue).sum();
      chartEntryLabelAnzahlenAnteiligFormatted.addAll(formatEntriesFuerRaeume(anzahlProRaum));
    }

    String chartEntryLabelMsgKey = "niederschrift.statusuebersicht.entry.label";

    if (!chartEntryLabelAnzahlenAnteiligFormatted.isEmpty()) {
      chartEntryLabelMsgKey += ".anteilig";
    }

    String chartEntryLabel = getMessage(chartEntryLabelMsgKey, getMessage(niederschriftStatus), format(chartEntrySumme),
        String.join(", ", chartEntryLabelAnzahlenAnteiligFormatted));

    modelBuilder.add(chartEntryLabel, chartEntrySumme, niederschriftStatus.getColor());
  }

  private List<String> formatEntriesFuerRaeume(Map<String, Long> anzahlProRaum) {
    List<String> raumEntriesFormatted = new ArrayList<>();
    for (Map.Entry<String, Long> raumAnzahlEntry : anzahlProRaum.entrySet()) {
      Long anzahl = raumAnzahlEntry.getValue();
      if (anzahl > 0) {
        raumEntriesFormatted.add(format(anzahl) + " " + raumAnzahlEntry.getKey());
      }
    }
    return raumEntriesFormatted;
  }
}
