
package de.ivu.elect.presentation.wahlbeteiligung.chart;

import static de.ivu.elect.presentation.wahlbeteiligung.WahlbeteiligungAuswertungStatusuebersichtViewHelper.isGebietRelevant;
import static de.ivu.elect.presentation.wahlbeteiligung.status.WahlbeteiligungErfassungsstatus.ERFASST;
import static de.ivu.elect.presentation.wahlbeteiligung.status.WahlbeteiligungErfassungsstatus.NICHT_ERFASST;
import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.time.DateUtils.isSameDay;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlbeteiligung.boundary.WahlbeteiligungAuswertungExtendedDAO;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.faces.UserLocale;
import de.ivu.elect.jee.presentation.charts.PieChartModelBuilder;
import de.ivu.elect.presentation.security.EinsehenGebietSecurity;
import de.ivu.elect.presentation.security.GebietSecurity;
import de.ivu.elect.presentation.wahlbeteiligung.status.WahlbeteiligungErfassungsstatus;

public class WahlbeteiligungAuswertungChartBuilder {

  @Inject
  private transient Messages messages;

  @Inject
  private transient UserLocale userLocale;

  @Inject
  private transient WahlbeteiligungAuswertungExtendedDAO wahlbeteiligungAuswertungDAO;

  @Inject
  private transient WahldurchfuehrungsgebietExtendedDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient GebietExtendedDAO gebietExtendedDAO;

  @Inject
  private transient GebietSecurity gebietSecurity;

  public WahlbeteiligungAuswertungChartBuilder() {
    super();
  }

  public List<WahlbeteiligungAuswertungChart> buildCharts(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, @Nullable WahlbeteiligungAuswertung ausgewaehlteAuswertung) {
    Wahl wahl = wahldurchfuehrungsgebiet.getWahl();

    EinsehenGebietSecurity einsehenGebietSecurity = gebietSecurity.getEinsehenGebietSecurity();
    Predicate<Wahldurchfuehrungsgebiet> wahldurchfuehrungsgebietPredicate = gebiet -> isGebietRelevant(wahldurchfuehrungsgebiet, gebiet, einsehenGebietSecurity);

    List<WahlbeteiligungAuswertungChart> result = new ArrayList<>();

    List<Wahldurchfuehrungsgebiet> erfassungsgebiete = wahldurchfuehrungsgebiet.getErfassungsgebieteUnterhalb(gebietExtendedDAO).stream()
        .filter(Wahldurchfuehrungsgebiet::isWahlbeteiligungErfassungsgebiet).filter(wahldurchfuehrungsgebietPredicate).collect(Collectors.toList());

    Collection<WahlbeteiligungAuswertung> auswertungen;

    if (nonNull(ausgewaehlteAuswertung)) {
      auswertungen = Collections.singletonList(ausgewaehlteAuswertung);
    } else {
      auswertungen = wahlbeteiligungAuswertungDAO.findByWahl(wahl).stream().sorted((auswertungA, auswertungB) -> auswertungA.getDatum().compareTo(auswertungB.getDatum())).collect(Collectors.toList());
    }

    for (WahlbeteiligungAuswertung auswertung : auswertungen) {
      PieChartModelBuilder modelBuilder = PieChartModelBuilder.getDefaultInstance();

      Set<Wahldurchfuehrungsgebiet> erfassteGebiete = wahldurchfuehrungsgebietDAO.findByWahlbeteiligungErfasst(auswertung).stream().filter(wahldurchfuehrungsgebietPredicate)
          .collect(Collectors.toSet());

      addChartModel(modelBuilder, NICHT_ERFASST, erfassungsgebiete.size() - erfassteGebiete.size());
      addChartModel(modelBuilder, ERFASST, erfassteGebiete.size());

      result.add(new WahlbeteiligungAuswertungChart(auswertung.getPk(), getChartHeader(wahl, auswertung), modelBuilder.buildModel()));
    }

    return result;
  }

  private void addChartModel(PieChartModelBuilder builder, WahlbeteiligungErfassungsstatus status, int anzahl) {
    builder.add(getMessage(status.getPieChartLabel(), anzahl), anzahl, status.getPieChartColor());
  }

  private String getChartHeader(Wahl wahl, WahlbeteiligungAuswertung auswertung) {
    if (isSameDay(auswertung.getDatum(), wahl.getWahldatum())) {
      return getMessage("wahlbeteiligung.auswertung.statusuebersicht.chart.header.nur.uhrzeit", userLocale.formatTimeHHmm(auswertung.getDatum()));
    }

    return getMessage("wahlbeteiligung.auswertung.statusuebersicht.chart.header", userLocale.formatDate(wahl.getWahldatum()), userLocale.formatTimeHHmm(auswertung.getDatum()));
  }

  private String getMessage(String key, Object... args) {
    return messages.getMessageForMessageKey(key, args);
  }
}
