
package de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.inject.Named;

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

import de.ivu.elect.business.dokumente.boundary.AbstractDokumentGenerator;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisSessionSelect;
import de.ivu.elect.business.ergebnis.boundary.GesamtErgebnisDokumentContext;
import de.ivu.elect.business.ergebnis.boundary.GesamtErgebnisDokumentGenerator;
import de.ivu.elect.business.ergebnis.control.ErgebnisExchangeContext;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartCreator;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartExtendedDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartTemplate;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatterKandidaturFormatDarstellung;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangKonfiguration;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.dokumente.AbstractDokumentErzeugenView;
import de.ivu.elect.presentation.dokumente.ElectDokumentContextGenerator;
import de.ivu.elect.presentation.ergebnis.ErgebnisStatusInfo;
import de.ivu.elect.presentation.ergebnis.ViewHavingErgebnisStatusInfo;
import de.ivu.elect.presentation.ergebnis.WasErgebnisStatusInfo;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.wahlvorschlag.form.WahlvorschlagDokumentErzeugenViewFormBuilder;

@OnlineHilfeId("158")
@GroupedConversationScoped
@ConversationGroup(GesamtErgebnisDokumentErzeugenView.class)
@Named(GesamtErgebnisDokumentErzeugenView.COMPONENT_NAME)
@View(viewId = GesamtErgebnisDokumentErzeugenView.VIEW_ID, useCase = UseCasePermission.DOKUMENT_ERZEUGEN_GESAMT_ERGEBNIS)
public class GesamtErgebnisDokumentErzeugenView extends AbstractDokumentErzeugenView<Ergebnis, GesamtErgebnisDokumentContext> implements ViewHavingErgebnisStatusInfo {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "gesamtErgebnisDokumentErzeugenView";

  public static final String VIEW_ID = "/ergebnis/gesamt-ergebnis-dokument-erzeugen-view.xhtml";

  @Inject
  private transient ErgebnisSessionSelect ergebnisSessionSelect;

  @Inject
  private transient ElectDokumentContextGenerator electDokumentContextGenerator;

  @Inject
  private transient GesamtErgebnisDokumentGenerator gesamtErgebnisDokumentGenerator;

  @Inject
  private transient GebietsartCreator gebietsartCreator;

  @Inject
  private transient GebietsartExtendedDAO gebietsartExtendedDAO;

  @Inject
  private transient WahlvorschlagDokumentErzeugenViewFormBuilder wahlvorschlagDokumentErzeugenViewFormBuilder;

  @Inject
  private transient ErgebniseingangKonfiguration ergebniseingangKonfiguration;

  private StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung;

  private Map<GebietsartTemplate, GebietsartAuswahlProperty> gebietsartAuswahlProperties;

  public GesamtErgebnisDokumentErzeugenView() {
    super();
  }

  @Override
  protected UseCasePermission getRequiredPermission() {
    return UseCasePermission.DOKUMENT_ERZEUGEN_GESAMT_ERGEBNIS;
  }

  @Override
  public String getViewId() {
    return VIEW_ID;
  }

  @Override
  @PreConditionCheck
  public String checkPreCondition() {
    if (isErgebnisSelected()) {
      return super.checkPreCondition();
    }

    return startViewResolver.getStartViewId();
  }

  public String getGebietName() {
    return getSelectedGebietNameFormatted();
  }

  @Override
  protected List<Ergebnis> getEntities() {
    return singletonList(getSelectedErgebnis());
  }

  @Override
  protected AbstractDokumentGenerator<Ergebnis, GesamtErgebnisDokumentContext> getDokumentGenerator() {
    return gesamtErgebnisDokumentGenerator;
  }

  @Override
  protected GesamtErgebnisDokumentContext getContext() {
    return createContext(new ErgebnisExchangeContext(getSelectedWahl(), asList(getSelectedGebiet()), getKandidaturFormatDarstellung()), getGebieteMitDetailsGebietsarten());
  }

  public GesamtErgebnisDokumentContext createContext(ErgebnisExchangeContext ergebnisExchangeContext, Collection<GebietsartTemplate> gebieteMitDetailsGebietsarten) {
    return new GesamtErgebnisDokumentContext(electDokumentContextGenerator.createElectDokumentContext(), ergebnisExchangeContext, gebieteMitDetailsGebietsarten);
  }

  @Override
  public void addDokumentParameterProperties(FormBuilder formBuilder) {
    super.addDokumentParameterProperties(formBuilder);

    wahlvorschlagDokumentErzeugenViewFormBuilder.addPropertyKandidaturFormatDarstellung(formBuilder, getSelectedWahl(), this::getKandidaturFormatDarstellung, this::setKandidaturFormatDarstellung,
        true); // ELECT-9339

    List<GebietsartTemplate> gebietsartTemplates = collectAllGebietsartTemplates();

    gebietsartAuswahlProperties = new HashMap<>();

    if (!gebietsartTemplates.isEmpty()) {
      formBuilder.addSeparator("gesamtergebnis.dokument.details.separator");

      for (GebietsartTemplate gebietsartTemplate : gebietsartTemplates) {
        GebietsartAuswahlProperty gebietsartAuswahlProperty = new GebietsartAuswahlProperty(gebietsartTemplate, getMessages());
        gebietsartAuswahlProperty.setValue(true); // ELECT-16277

        formBuilder.addProperty(gebietsartAuswahlProperty);

        gebietsartAuswahlProperties.put(gebietsartTemplate, gebietsartAuswahlProperty);
      }
    }
  }

  public StimmzettelFormatterKandidaturFormatDarstellung getKandidaturFormatDarstellung() {
    return kandidaturFormatDarstellung;
  }

  public void setKandidaturFormatDarstellung(StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung) {
    this.kandidaturFormatDarstellung = kandidaturFormatDarstellung;
  }

  private Set<GebietsartTemplate> getGebieteMitDetailsGebietsarten() {
    Set<GebietsartTemplate> result = new HashSet<>();

    if (gebietsartAuswahlProperties != null) {
      for (Entry<GebietsartTemplate, GebietsartAuswahlProperty> entry : gebietsartAuswahlProperties.entrySet()) {
        if (entry.getValue().getValue()) {
          result.add(entry.getKey());
        }
      }
    }

    return result;
  }

  public List<GebietsartTemplate> collectAllGebietsartTemplates() {
    Mandant mandant = getMandant();

    if (mandant == null) {
      return emptyList(); // NPE nach Logout
    }

    Wahl selectedWahl = getSelectedWahl();

    if (selectedWahl == null) {
      return emptyList();
    }

    Collection< ? extends GebietsartTemplate> gebietsarten = gebietsartCreator.getGebietsartTemplates(mandant);

    return gebietsartExtendedDAO.findByGebieteInWahl(selectedWahl).stream().map(gebietsart -> gebietsart.getCustomGebietsartTemplate(gebietsarten)).distinct().collect(Collectors.toList());
  }

  //ELECT-12371
  //  public List<GebietsartTemplate> collectAllGebietsartTemplates() {
  //
  //
  //    List<GebietsartTemplate> result = new ArrayList<>();
  //
  //    Mandant mandant = getMandant();
  //    if (mandant == null) {
  //      return emptyList(); // NPE nach Logout
  //    }
  //    Collection<? extends GebietsartTemplate> gebietsarten = gebietsartCreator.getGebietsartTemplates(mandant);
  //
  //    List<Gebiet> gebieteSortiert = new ArrayList<>(collectAllGebiete());
  //    Collections.sort(gebieteSortiert, new GebietByBreadthFirstComparator());
  //
  //    for (Gebiet gebiet : gebieteSortiert) {
  //      GebietsartTemplate template = gebiet.getGebietsart().getCustomGebietsartTemplate(gebietsarten);
  //
  //      if (!result.contains(template)) {
  //        result.add(template);
  //      }
  //    }
  //
  //    return result;
  //  }
  //
  //  private Collection< ? extends Gebiet> collectAllGebiete() {
  //    if (isWahlSelected()) {
  //      return gebietExtendedDAO.findByWahl(getSelectedWahl());
  //    }
  //
  //    return new ArrayList<>();
  //  }

  @Override
  public ErgebnisStatusInfo getErgebnisStatusInfo() {
    return new WasErgebnisStatusInfo(getMessages(), getSelectedWahl(), ergebniseingangKonfiguration, getSelectedErgebnis());
  }

  private boolean isErgebnisSelected() {
    return ergebnisSessionSelect.isSelected();
  }

  private Ergebnis getSelectedErgebnis() {
    return ergebnisSessionSelect.getEntity();
  }
}
