
package de.ivu.elect.core.exchange.stimmen.csv.dynamic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformationResolver;
import de.ivu.elect.business.gebietsbaum.control.GebietByDepthFirstComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaBooleanProperty;
import de.ivu.elect.jee.presentation.dynamicform.PropertyType;
import de.ivu.elect.presentation.LambdaEntitySelectManyProperty;


import static org.apache.commons.lang3.StringUtils.defaultIfBlank;

public class ConfigDynamicStimmenCsvExportMapper extends AbstractDynamicStimmenCsvExportMapper<DefaultDynamicStimmenExportDTOFactory> {

  private static final long serialVersionUID = 1L;

  public static final String FORMAT_NAME = "file.format.stimmen.ergebins.exchange.dynamic.config";

  public static final String CONFIG_DYNAMIC_STIMMEN_CSV_EXPORT_MAPPER_GEBIETSARTEN = "ConfigDynamicStimmenCsvExportMapper.gebietsarten";

  public static final String CONFIG_DYNAMIC_STIMMEN = "ConfigDynamicStimmenCsvExportMapper.CONFIG_DYNAMIC_STIMMEN";

  @Inject
  protected transient WahlverwaltungGebietInformationResolver wahlverwaltungGebietInformationResolver;

  @Inject
  protected transient ConfigDynamicStimmenCsvExportMapperHelper configDynamicStimmenCsvExportMapperHelper;

  @Inject
  protected transient Messages messages;

  public ConfigDynamicStimmenCsvExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(ErgebnisExportContext context) {
    Wahl wahl = context.getWahl();

    return wahl != null && (wahl.isReferendum() || wahl.isWahlMitDirektkandidatengebieten() || wahl.isWahlMitListengebieten()); // ELECT-11886
  }

  @Override
  protected String getFileFormatName() {
    return FORMAT_NAME;
  }

  @Override
  public void addProperties(FormBuilder formBuilder, ErgebnisExportContext context, @Nullable Datei datei) {
    super.addProperties(formBuilder, context, datei);
    List<Gebietsart> gebietsarten = configDynamicStimmenCsvExportMapperHelper.findByGebieteInWahl(context.getWahl());
    if (!gebietsarten.isEmpty()) {
      formBuilder.addProperty(
          new LambdaEntitySelectManyProperty<>(gebietsarten, PropertyType.SELECT_MANY_CHECKBOX_MENU, values -> setGebietsarten(values, context),
              () -> getGebietsarten(context), this::getNameFuerGebietsart, "ConfigDynamicStimmenCsvExportMapper.gebietsarten",
              false));
    }

    ConfigDynamicStimmen configDynamicStimmen = getConfigDynamicStimmen(context);
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.gemeindeAnzeigen"), false,
        configDynamicStimmen::setGemeindeAusgeben, configDynamicStimmen::isGemeindeAusgeben));
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.gemeindeNameAnzeigen"), false,
        configDynamicStimmen::setGemeindeNameAusgeben, configDynamicStimmen::isGemeindeNameAusgeben));
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.wahlkreisAusgeben"), false,
        configDynamicStimmen::setWahlkreisAusgeben, configDynamicStimmen::isWahlkreisAusgeben));
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.erfassungsgebietnameAusgeben"),
        false,
        configDynamicStimmen::setErfassungsgebietNameAusgeben, configDynamicStimmen::isErfassungsgebietNameAusgeben));
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.bezirksnummerAusgaben"), false,
        configDynamicStimmen::setBezirksnummerAusgeben, configDynamicStimmen::isBezirksnummerAusgeben));
    formBuilder.addProperty(new LambdaBooleanProperty(messages.getMessageForMessageKey("ConfigDynamicStimmenCsvExportMapper.ausbleibendAusgeben"), false,
        configDynamicStimmen::setAusbleibendAusgeben, configDynamicStimmen::isAusbleibendAusgeben));

  }

  private Collection<Gebietsart> getGebietsarten(ErgebnisExportContext context) {
    Collection values = context.get(CONFIG_DYNAMIC_STIMMEN_CSV_EXPORT_MAPPER_GEBIETSARTEN, Collection.class);
    if (values == null) {
      return new ArrayList<>();
    }
    return values;
  }

  private void setGebietsarten(Collection<Gebietsart> values, ErgebnisExportContext context) {
    context.put(CONFIG_DYNAMIC_STIMMEN_CSV_EXPORT_MAPPER_GEBIETSARTEN, values);
  }

  protected ConfigDynamicStimmen getConfigDynamicStimmen(ErgebnisExportContext context) {
    ConfigDynamicStimmen result = context.get(CONFIG_DYNAMIC_STIMMEN, ConfigDynamicStimmen.class);
    if (result == null) {
      result = new ConfigDynamicStimmen();
      context.put(CONFIG_DYNAMIC_STIMMEN, result);
    }
    return result;
  }

  private String getNameFuerGebietsart(Gebietsart gebietsart) {
    return defaultIfBlank(gebietsart.getTitel(), gebietsart.getName());
  }

  @Override
  protected List<Gebiet> collectGebiete(ErgebnisDaten ergebnisDaten, Wahldurchfuehrungsgebiet wurzelgebiet, ErgebnisExportContext context) {
    HashSet<Gebietsart> gebietsarten = new HashSet<>(getGebietsarten(context));
    return ergebnisDaten.getGebiete().stream().filter(g -> gebietsarten.isEmpty() || gebietsarten.contains(g.getGebietsart()))
        .sorted(GebietByDepthFirstComparator.INSTANCE).collect(Collectors.toList());
  }

  @Override
  protected DefaultDynamicStimmenExportDTOFactory createDtoFactory(Wahldurchfuehrungsgebiet wurzelgebiet, ErgebnisDaten ergebnisDaten, ErgebnisExportContext context) {
    return new ConfigDynamicStimmenExportDTOFactory(wurzelgebiet, new DynamicStimmenExchangeErgebnisDatenWrapper(ergebnisDaten),
        listenwahlStimmeingabeKonfiguration,
        wahlverwaltungGebietInformationResolver, getConfigDynamicStimmen(context));
  }

  @Override
  protected boolean isAusbleibdendeGebieteExportieren(ErgebnisExportContext context) {
    return getConfigDynamicStimmen(context).isAusbleibendAusgeben();
  }
}
