
package de.ivu.elect.dokumente.wahl;

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

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.dokumente.boundary.AbstractDokumentVorlageDAO;
import de.ivu.elect.business.dokumente.control.ElectDokumentContext;
import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.dokumente.entity.DokumentVorlageArt;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.wahl.boundary.AbstractWahlDAO;
import de.ivu.elect.business.wahl.boundary.NlExportArtefaktNachSystemExportstatusHashCode;
import de.ivu.elect.business.wahl.control.AbstractNlExportArtefaktNachSystemExportstatusExportContext;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.dokumente.konverter.AbstractDokumentGeneratorDocumentMapper;
import de.ivu.elect.dokumente.konverter.DokumentGeneratorDocumentMapperDokumentVorlagen;

public class NlExportArtefaktNachSystemExportstatussDocumentExportMapper<C extends AbstractNlExportArtefaktNachSystemExportstatusExportContext, E, D extends ElectDokumentContext> {

  private static final Logger LOG = LoggerFactory.getLogger(NlExportArtefaktNachSystemExportstatussDocumentExportMapper.class);

  private final AbstractWahlDAO wahlDAO;

  private final String fileFormatName;

  private final AbstractDokumentVorlageDAO dokumentVorlageDAO;

  private final String dokumentVorlageNameInfix;

  private final AbstractDokumentGeneratorDocumentMapper<C, E, D> dokumentGeneratorDocumentMapper;

  public NlExportArtefaktNachSystemExportstatussDocumentExportMapper(AbstractWahlDAO wahlDAO, String fileFormatName, AbstractDokumentVorlageDAO dokumentVorlageDAO, String dokumentVorlageNameInfix,
      AbstractDokumentGeneratorDocumentMapper<C, E, D> dokumentGeneratorDocumentMapper) {
    super();

    this.wahlDAO = wahlDAO;

    this.fileFormatName = fileFormatName;

    this.dokumentVorlageDAO = dokumentVorlageDAO;
    this.dokumentVorlageNameInfix = dokumentVorlageNameInfix;

    this.dokumentGeneratorDocumentMapper = dokumentGeneratorDocumentMapper;
  }

  public void serialize(OutputStream os, C context, E dokumentEntities, D dokumentContext, boolean closeOutputStream) throws Exception {
    Wahl wahl = wahlDAO.attach(context.getWahl());

    DokumentVorlage dokumentVorlage = getDokumentVorlage(wahl, dokumentVorlageDAO);

    if (dokumentVorlage != null) {
      FileType targetFileType = context.getTargetFileType().orElse(getDefaultTargetFileType());

      Map<FileFormat, Collection<NlExportArtefaktNachSystemExportstatusHashCode>> hashCodesPerFileFormat = context.getHashCodesPerFileFormat();

      dokumentContext.putAll(context.getContextParameters()); // ELECT-10450, Parameter zum Signieren mitgeben!
      dokumentContext.put(AbstractNlExportArtefaktNachSystemExportstatusExportContext.PARAM_KEY_HASH_CODES_PER_FILE_FORMAT, hashCodesPerFileFormat); // ELECT-10233

      LOG.info("Erzeuge Dokument [" //
          + "wahl = " + wahl.getName() + ", " //
          + "signierung deaktiviert = " + Boolean.TRUE.equals(dokumentContext.get(EmlExportMapper.EML_SIGN_SKIP_KEY, Boolean.class)) + ", " //
          + "dokumentVorlage = [art = " + dokumentVorlage.getDokumentVorlageArt() + ", name = " + dokumentVorlage.getName() + "], " //
          + "fileFormat = " + fileFormatName + ", "//
          + "ausgabedateityp = " + targetFileType + ", " //
          + "hashCodesPerFileFormat = " + hashCodesPerFileFormat.entrySet().size() //
          + "]");

      getDokumentGeneratorDocumentMapper().serialize(os, context, fileFormatName, targetFileType, dokumentContext, dokumentEntities, dokumentVorlage, closeOutputStream);

      context.putAll(dokumentContext.getContextParameters()); // ELECT-10670, gecachtes Dokument ggf. wiederverwenden...
    } else {
      LOG.error("Dokumentvorlage NICHT gefunden [art = " + getDokumentVorlageArt() + ", name = " + getDokumentVorlageNameInfix() + ", type = " + getDokumentVorlageFileType().getFileExtension() + "]");
    }
  }

  public FileType getDefaultTargetFileType() {
    return FileType.ODT;
  }

  public List<FileType> getTargetFileTypes() {
    List<FileType> result = new ArrayList<>();
    result.add(getDefaultTargetFileType());

    if (!result.contains(FileType.DOCX) && isTargetFileTypeSupported(FileType.DOCX)) { // ELECT-10764
      result.add(FileType.DOCX);
    }

    if (!result.contains(FileType.PDF) && isTargetFileTypeSupported(FileType.PDF)) { // ELECTVAPP-465
      result.add(FileType.PDF);
    }

    return result;
  }

  // Cf. NlDokumentGenerierenSupportedOpenOfficeFileFormats#getSupportedFileTypes!!!
  public boolean isTargetFileTypeSupported(FileType fileType) {
    return getDokumentGeneratorDocumentMapper().getTargetFileTypesSupported().contains(fileType);
  }

  private DokumentVorlage getDokumentVorlage(Wahl wahl, AbstractDokumentVorlageDAO dokumentVorlageDAO) {
    return new DokumentGeneratorDocumentMapperDokumentVorlagen(wahl, dokumentVorlageDAO, getDokumentVorlageArt(), getDokumentVorlageFileType(), getDokumentVorlageNameInfix(),
        getDokumentVorlageNameMatcher()).getDokumentVorlage();
  }

  public DokumentVorlageArt getDokumentVorlageArt() {
    return getDokumentGeneratorDocumentMapper().getDokumentVorlageArt();
  }

  public FileType getDokumentVorlageFileType() {
    return getDokumentGeneratorDocumentMapper().getDokumentVorlageFileType();
  }

  public String getDokumentVorlageNameInfix() {
    return dokumentVorlageNameInfix;
  }

  public BiPredicate<String, String> getDokumentVorlageNameMatcher() {
    return StringUtils::equalsAnyIgnoreCase; // Model I vs. Model II...
  }

  public AbstractDokumentGeneratorDocumentMapper<C, E, D> getDokumentGeneratorDocumentMapper() {
    return dokumentGeneratorDocumentMapper;
  }
}
