
package de.ivu.elect.was.exchange.ergebnis.eml;

import java.io.Serializable;
import java.util.List;
import java.util.function.Supplier;

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

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.business.CurrentCustomer;
import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.ergebnis.boundary.NlErgebniseingabestatuswechelPruefer;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportObject;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.boundary.NlGebietDarstellungNummerFormatter;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlParameterLoader;
import de.ivu.elect.business.wahl.entity.WahlParameterWerte;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.nl.eml.readable.AbstractEml5xxContestWrapper;
import de.ivu.elect.nl.eml.readable.AbstractEmlElectionWrapper;
import de.ivu.elect.nl.eml.readable.ManagingAuthorityWrapper;
import de.ivu.elect.presentation.ergebnis.exchange.NlErgebnisExportView;
import de.ivu.elect.was.exchange.ergebnis.ErgebnisExportMapper;
import de.ivu.elect.was.exchange.wahl.EmlCommonMapper;

public abstract class AbstractEml5xxErgebnisExportMapper implements Serializable, ErgebnisExportMapper, EmlExportMapper {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient NlErgebniseingabestatuswechelPruefer nlErgebniseingabestatuswechelPruefer;

  @Inject
  private transient CurrentCustomer currentCustomer;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient Messages messages;

  @Inject
  private transient EmlCommonMapper emlCommonMapper;

  @Inject
  protected transient NlGebietDarstellungNummerFormatter nlGebietDarstellungNummerFormatter;

  @Inject
  private transient WahlParameterLoader wahlParameterLoader;

  protected AbstractEml5xxErgebnisExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(ErgebnisExportContext context) {
    return context.getWahl() != null && isWahlebenePassend(context.getWahl()) && isGebietAuswahlNotwendigUndVorhanden(
        context) && isErgebnisVorhandenWennNotwendig(context.getErgebnis());
  }

  public String createEmlXmlFileName(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return createSimpleFileName(ergebnisExportObject, context) + EML_FILE_EXTENSION;
  }

  public String createEmlZipFileName(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return createSimpleFileName(ergebnisExportObject, context) + "." + FileType.ZIP.getFileExtension();
  }

  protected abstract String createSimpleFileName(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context);

  private boolean isErgebnisVorhandenWennNotwendig(Ergebnis ergebnis) {
    return !isErgebnisNotwendig() || isErgebnisVorhanden(ergebnis);
  }

  protected boolean isErgebnisVorhanden(Ergebnis ergebnis) {
    return nlErgebniseingabestatuswechelPruefer.isErgebnisAuswertungMoeglich(ergebnis);
  }

  protected abstract boolean isErgebnisNotwendig();

  // ELECT-13360, EILANDSRAAD wie GEMEENTERAAD behandeln...
  protected boolean isWahlebeneIrrelevant(Wahl wahl) {
    NlWahlart nlWahlart = NlWahlart.valueOf(wahl);

    return !NlWahlart.UNBEKANNT.equals(nlWahlart) && !nlWahlart.isWahlartMitMehrerenWahlebenen();
  }

  protected boolean isWahlebenePassend(Wahl wahl) {
    boolean isPSB = isPSB(wahl);
    boolean isHSB = isHSB(wahl);
    boolean isCSB = isCSB(wahl);

    if (isPsbNotwendig() && (!isPSB || isHSB || isCSB)) {
      return false;
    }

    if (isHsbNotwendig() && (!isHSB || isCSB)) {
      return false;
    }

    if (isCsbNotwendig() && !isCSB) {
      return false;
    }

    return true;
  }

  protected boolean isPSB(Wahl wahl) {
    return NlWahlart.isWasPSB(wahl, getCustomer());
  }

  protected abstract boolean isPsbNotwendig();

  protected boolean isHSB(Wahl wahl) {
    return NlWahlart.isWasHSB(wahl, getCustomer());
  }

  protected abstract boolean isHsbNotwendig();

  protected boolean isCSB(Wahl wahl) {
    return NlWahlart.isWasCSB(wahl, getCustomer());
  }

  protected abstract boolean isCsbNotwendig();

  protected boolean isGebietAuswahlNotwendigUndVorhanden(ErgebnisExportContext context) {
    return !isGebietAuswahlNotwendig() || isGebietAusgewaehlt(context);
  }

  private boolean isGebietAusgewaehlt(ErgebnisExportContext context) {
    return getAusgewaehltesGebietPK(context) != null;
  }

  protected abstract boolean isGebietAuswahlNotwendig();

  protected abstract boolean isErfassungsgebietAuswahlNotwendig();

  @Nullable
  protected abstract Wahldurchfuehrungsgebiet bestimmeGebietFuerDaten(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context);

  protected Wahldurchfuehrungsgebiet bestimmeOberstesGebiet(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return ergebnisExportObject.getErgebnisDaten().getWurzelgebiet();
  }

  @Nullable
  protected GebietPK getAusgewaehltesGebietPK(ErgebnisExportContext context) {
    GebietPK gebietPK = context.get(NlErgebnisExportView.NL_ERGEBNIS_EXPORT_CONTEXT_PARAM_SELECTED_GEBIET_PK, GebietPK.class);

    if (gebietPK != null && isErfassungsgebietAuswahlNotwendig()) {
      if (!wahldurchfuehrungsgebietDAO.findByPrimaryKey(gebietPK).isErfassungsgebiet()) {
        return null;
      }
    }

    return gebietPK;
  }

  protected void mappeWahldaten(ErgebnisExportObject ergebnisExportObject, AbstractEmlElectionWrapper emlElectionWrapper, Gebiet gebiet, Supplier<List<Gebiet>> alleGebiete) {
    emlCommonMapper.mappeWahldaten(ergebnisExportObject.getErgebnisDaten().getWahl(), emlElectionWrapper, gebiet, alleGebiete);
  }

  protected void fillManagingAuthority(ManagingAuthorityWrapper managingAuthority, ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    fillManagingAuthority(managingAuthority, bestimmeGebietFuerDaten(ergebnisExportObject, context), bestimmeOberstesGebiet(ergebnisExportObject, context), nlGebietDarstellungNummerFormatter,
        getAuthorityIdPrefix(ergebnisExportObject), createdByAuthorityIdPrefix(ergebnisExportObject));
  }

  protected abstract String getAuthorityIdPrefix(ErgebnisExportObject ergebnisExportObject);

  protected abstract String createdByAuthorityIdPrefix(ErgebnisExportObject ergebnisExportObject);

  protected String getMessage(String msgKey, Object... params) {
    return getMessages().getMessageForMessageKey(msgKey, params);
  }

  protected Messages getMessages() {
    return messages;
  }

  protected Customer getCustomer() {
    return currentCustomer.getCustomer();
  }

  protected void fillContest(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context, Wahl wahl,
                             AbstractEml5xxContestWrapper<?> eml510ContestWrapper) {
    // "geen", "alle", "nummer"/"name""
    if (isWahlebeneIrrelevant(wahl)) {
      eml510ContestWrapper.setContestId("geen"); // ELECTVAPP-491
    } else if (NlWahlart.isWasCSB(wahl, currentCustomer.getCustomer()) && NlWahlart.valueOf(wahl).isContestidentifierAlleIn5xxCsb()) {
      eml510ContestWrapper.setContestId("alle"); // ELECTVAPP-1335 ELECT-13754
    } else {
      eml510ContestWrapper.setContestId(bestimmeContestId(ergebnisExportObject, context));
      eml510ContestWrapper.setContestName(bestimmeContestName(ergebnisExportObject, context));
    }
  }

  protected String bestimmeContestName(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return wahlParameterLoader.resolveStringValue(ergebnisExportObject.getErgebnisDaten().getWahl(), WahlParameterWerte.DOKUMENT_PLATZHALTER_WAHLKREIS_NAME);
  }

  protected String bestimmeContestId(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return wahlParameterLoader.resolveStringValue(ergebnisExportObject.getErgebnisDaten().getWahl(), WahlParameterWerte.DOKUMENT_PLATZHALTER_WAHLKREIS_NUMMER);
  }

}
