
package de.ivu.elect.presentation.kandidatur;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang3.StringUtils;
import org.apache.deltaspike.core.api.scope.ConversationGroup;
import org.apache.deltaspike.core.api.scope.ViewAccessScoped;

import de.ivu.elect.business.gebietsbaum.boundary.GebietSelectChangeEvent;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.kandidatur.boundary.KandidaturNachErfassungsgebietStimmenSearch;
import de.ivu.elect.business.kandidatur.boundary.KandidaturNachErfassungsgebietStimmenSearchParameters;
import de.ivu.elect.business.kandidatur.boundary.ListenkandidaturExtendedDAO;
import de.ivu.elect.business.kandidatur.control.ListenkandidaturByStimmzettelPositionComparator;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturKumulierteStimmen;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.stimmzettel.boundary.EntityAufStimmzettelDatenExtendedDAOFactory;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStimmzettelPosition;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.ergebnis.AbstractKumulierteStimmenSearchView;
import de.ivu.elect.presentation.gruppe.form.GruppeSearchProperty;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.kandidatur.form.KandidaturSearchProperty;
import de.ivu.elect.presentation.kandidatur.table.ListenkandidaturKumulierteStimmenColumnBuilder;

@OnlineHilfeId("257")
@ViewAccessScoped
@View(viewId = ListenkandidaturNachErfassungsgebietStimmenSearchView.VIEW_ID, useCase = UseCasePermission.ERGEBNIS_GRUPPEN_NACH_GEBIETEN_ANZEIGEN)
@Named(ListenkandidaturNachErfassungsgebietStimmenSearchView.COMPONENT_NAME)
public class ListenkandidaturNachErfassungsgebietStimmenSearchView extends AbstractKumulierteStimmenSearchView<KandidaturNachErfassungsgebietStimmenSearchParameters, KandidaturKumulierteStimmen> {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "listenkandidaturNachErfassungsgebietStimmenSearchView";

  public static final String VIEW_ID = "/kandidatur/listenkandidatur-nach-erfassungsgebiet-stimmen-search.xhtml";

  @Inject
  private transient ListenkandidaturExtendedDAO listenkandidaturExtendedDAO;

  @Inject
  private transient EntityAufStimmzettelDatenExtendedDAOFactory entityAufStimmzettelDatenExtendedDAOFactory;

  @Inject
  private transient StimmzettelFormatter stimmzettelFormatter;

  @Inject
  private transient KandidaturNachErfassungsgebietStimmenSearch listenkandidaturNachErfassungsgebietStimmenSearch;

  @Inject
  @ConversationGroup(KandidaturNachErfassungsgebietStimmenSearchParameters.class)
  private transient KandidaturNachErfassungsgebietStimmenSearchParameters listenkandidaturNachErfassungsgebietStimmenSearchParameters;

  @Inject
  private transient ListenkandidaturKumulierteStimmenColumnBuilder listenkandidaturKumulierteStimmenColumnBuilder;

  public ListenkandidaturNachErfassungsgebietStimmenSearchView() {
    super();
  }

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

  @Override
  protected void initSearchParametersByDefaults() {
    super.initSearchParametersByDefaults();

    if (!getPolitischeGruppen().isEmpty()) {
      listenkandidaturNachErfassungsgebietStimmenSearchParameters.setGruppe(getPolitischeGruppen().get(0));
    }
  }

  @Override
  protected KandidaturNachErfassungsgebietStimmenSearchParameters getSearchParametersInternal() {
    return listenkandidaturNachErfassungsgebietStimmenSearchParameters;
  }

  @Override
  protected KandidaturNachErfassungsgebietStimmenSearch getSearch() {
    return listenkandidaturNachErfassungsgebietStimmenSearch;
  }

  @Override
  protected ListenkandidaturKumulierteStimmenColumnBuilder getColumnBuilder() {
    return listenkandidaturKumulierteStimmenColumnBuilder;
  }

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

    formBuilder.addProperty(getSearchParameters().getGebietsauswahlProperty());
    formBuilder.addProperty(getSearchParameters().getStimmabgabeartProperty());

    GruppeSearchProperty<PolitischeGruppe> politischeGruppeSearchProperty = getSearchParameters().getPolitischeGruppeSearchProperty(getPolitischeGruppen());
    formBuilder.addProperty(politischeGruppeSearchProperty);

    formBuilder.addProperty(getSearchParameters().getKandidaturSearchProperty(politischeGruppeSearchProperty, getKandidaturenByGruppeFinder(), getKandidaturLabeler()))
        .withObservedProperties(politischeGruppeSearchProperty);
  }

  private Function<Gruppe, List<Kandidatur>> getKandidaturenByGruppeFinder() {
    return gruppe -> {
      if (Objects.isNull(gruppe)) {
        return new ArrayList<>();
      }
      return listenkandidaturExtendedDAO.findByGruppeAndUngleichStatus(gruppe, KandidaturStatus.NICHT_ZUGELASSEN).stream() //
          .filter(listenkandidatur -> listenkandidatur.getGebiet().isInGebietshierarchieUebergeordnetesGebietVon(getSelectedGebiet())
              || getSelectedGebiet().isInGebietshierarchieUebergeordnetesGebietVon(listenkandidatur.getGebiet()))
          .sorted(new ListenkandidaturByStimmzettelPositionComparator(getEntityAufStimmzettelDaten())) //
          .collect(Collectors.toList());
    };
  }

  private Function<Kandidatur, String> getKandidaturLabeler() {
    return kandidatur -> {
      Listenkandidatur listenkandidatur = kandidatur.castTo(Listenkandidatur.class).getEntity();
      String label = stimmzettelFormatter.getKandidaturNamePraesentation(listenkandidatur);

      EntityAufStimmzettelDaten entityAufStimmzettelDaten = getEntityAufStimmzettelDaten();

      WahlvorschlagStimmzettelPosition stimmzettelPosition = listenkandidatur.getListe().getStimmzettelPosition(entityAufStimmzettelDaten);

      String listenkandidaturStimmzettelPosition = listenkandidatur.getStimmzettelPosition(entityAufStimmzettelDaten).formatPosition(stimmzettelPosition);
      if (StringUtils.isNotBlank(listenkandidaturStimmzettelPosition)) {
        label = listenkandidaturStimmzettelPosition + " - " + label;
      }

      return label;
    };
  }

  private EntityAufStimmzettelDaten getEntityAufStimmzettelDaten() {
    return entityAufStimmzettelDatenExtendedDAOFactory.getEntityAufStimmzettelDaten();
  }

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

    GruppeSearchProperty<PolitischeGruppe> politischeGruppeSearchProperty = getSearchParameters().getPolitischeGruppeSearchProperty(getPolitischeGruppen());

    KandidaturSearchProperty kandidaturSearchProperty = getSearchParameters().getKandidaturSearchProperty(politischeGruppeSearchProperty, getKandidaturenByGruppeFinder(), getKandidaturLabeler());

    kandidaturSearchProperty.updateValues();
  }
}
