
package de.ivu.elect.was.exchange.wahl;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipOutputStream;

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

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.EmlExportMapperHelper;
import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.exchange.control.MappingException;
import de.ivu.elect.business.gebietsbaum.entity.AbstractGebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.security.boundary.EmlSignKeyService;
import de.ivu.elect.business.wahl.control.WahlExportContext;
import de.ivu.elect.business.wahl.control.WahlExportObject;
import de.ivu.elect.business.wahl.control.Wahldaten;
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.util.FileUtil;
import de.ivu.elect.wus.exchange.wahl.WahlExportMapper;


import static java.util.stream.Collectors.toList;

public class Eml110aZipWahlExportMapper implements WahlExportMapper, EmlExportMapper {

  public static final String EML_ID = "110a";

  public static final String EML_FILE_NAME_PREFIX = "Verkiezingsdefinitie";

  public static final String FILE_FORMAT_NAME = "eml.110a.file.format";

  public static final FileFormat FILE_FORMAT = new FileFormat(FILE_FORMAT_NAME, FileType.ZIP);

  @Inject
  private transient Eml110Mapper eml110Mapper;

  @Inject
  private transient EmlExportMapperHelper emlExportMapperHelper;

  @Inject
  private transient EmlSignKeyService emlSignKeyService;

  @Inject
  private transient Messages messages;

  public Eml110aZipWahlExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(WahlExportContext context) {
    return context.getWahl() != null;
  }

  @Override
  public FileFormat getFileFormat() {
    return FILE_FORMAT;
  }

  @Override
  public boolean isSignEml(Wahl wahl) {
    return false; // nicht notwendig https://support.elect-it.com/wiki/display/VAPP/EML-Import+validation
  }

  @Override
  public void addProperties(FormBuilder formBuilder, WahlExportContext context, @Nullable Datei datei) {
    addSignProperties(context.getWahl(), formBuilder, context, messages);
  }

  @Override
  public void serialize(WahlExportObject exportObject, OutputStream os, WahlExportContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    Wahldaten<Wahl, Gebiet> wahldaten = exportObject.getWahldaten();
    var wahl = wahldaten.getWahl();

    var wahlgebiete = bestimmeWahlgebiete(wahldaten);
    var singleEmlXmlFileExported = wahlgebiete.size() == 1;

    try (var zos = new ZipOutputStream(os)) {
      var privateKey = retrievePrivateKey(wahl, context, emlSignKeyService);
      var publicKey = retrievePublicKey(wahl, context, emlSignKeyService);
      var nlX509Metadata = retrieveNlX509Metadata(wahl, context, emlSignKeyService);

      for (var gebiet : wahlgebiete) {
        var emlWrapper = eml110Mapper.mappe(wahldaten, gebiet, context.getNow());

        emlExportMapperHelper.writeEml(emlWrapper, zos, createEmlXmlFileName(wahl, gebiet, singleEmlXmlFileExported), gebiet, context, privateKey, publicKey,
            nlX509Metadata, true /* ELECT-11335 */);
      }

      zos.finish();
    } catch (IOException ex) {
      throw new MappingException(ex.getMessage(), ex);
    }
  }

  protected String createEmlXmlFileName(Wahl wahl, Gebiet gebiet, boolean singleEmlXmlFileExported) {
    return createSimpleFileName(wahl, gebiet, singleEmlXmlFileExported) + EML_FILE_EXTENSION;
  }

  // ELECTVAPP-1564
  public String createEmlZipFileName(WahlExportObject exportObject, WahlExportContext context) {
    Wahldaten<Wahl, Gebiet> wahldaten = exportObject.getWahldaten();
    var wahl = wahldaten.getWahl();

    var emlZipSimpleFileName = createSimpleFileName(wahl);
    Set<String> emlXmlSimpleFileNames = new HashSet<>();

    var wahlgebiete = bestimmeWahlgebiete(wahldaten);
    var singleEmlXmlFileExported = wahlgebiete.size() == 1;

    for (var gebiet : wahlgebiete) {
      emlXmlSimpleFileNames.add(createSimpleFileName(wahl, gebiet, singleEmlXmlFileExported));
    }

    if (emlXmlSimpleFileNames.size() == 1) {
      emlZipSimpleFileName = emlXmlSimpleFileNames.iterator().next();
    }

    return emlZipSimpleFileName + "." + FileType.ZIP.getFileExtension();
  }

  private String createSimpleFileName(Wahl wahl, Gebiet gebiet, boolean singleEmlXmlFileExported) {
    var simpleFileName = createSimpleFileName(wahl);

    if (!singleEmlXmlFileExported) {
      simpleFileName += "_" + gebiet.getName();
    }

// vor ELECTVAPP-1728
//    if (!singleEmlXmlFileExported || !(NlWahlart.EERSTE_KAMER.equalsWahlart(wahl) || NlWahlart.TWEEDE_KAMER.equalsWahlart(wahl) || NlWahlart.EUROPEES_PARLEMENT.equalsWahlart(wahl))) {
//      simpleFileName += "_" + gebiet.getName();
//    }

    return FileUtil.normalizeZipEntryNamePreserveCase(simpleFileName);
  }

  private String createSimpleFileName(Wahl wahl) {
    return FileUtil.normalizeZipEntryNamePreserveCase(EML_FILE_NAME_PREFIX + "_" + wahl.getKennzeichen());
    // vor ELECTVAPP-1728
//
//    String wahlartKennzeichen = wahl.getWahlart().getKennzeichen();
//    int wahljahr = wahl.getWahljahr();
//
//    return FileUtil.normalizeZipEntryNamePreserveCase(EML_FILE_NAME_PREFIX + "_" + wahlartKennzeichen + wahljahr);
  }

  public List<Gebiet> bestimmeWahlgebiete(Wahldaten<Wahl, Gebiet> wahldaten) {
    return wahldaten.getGebiete().stream().filter(AbstractGebiet::isWahlgebiet).collect(toList());
  }
}
