
package de.ivu.elect.business.exchange.control;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.primefaces.model.DefaultStreamedContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.datei.boundary.DateiExportDAO;
import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.datei.entity.DateiExportPK;
import de.ivu.elect.business.exchange.entity.DateienExportierenBackgroundServiceContext;
import de.ivu.elect.business.exchange.entity.DateienExportierenBackgroundServiceExportContext;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlOderWahltermin;
import de.ivu.elect.business.wahl.entity.WahlPK;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.business.wahl.entity.WahlterminPK;
import de.ivu.elect.jee.cdi.BeanManagerUtil;


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

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class DateienExportierenBackgroundService extends AbstractDateiExchangeBackgroundService {

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

  @Inject
  private transient DateiExportDAO dateiExportDAO;

  @Inject
  private transient ImportExportStreamCreator streamCreator;

  public DateienExportierenBackgroundService() {
    super();
  }

  public boolean exportiere(WahlPK wahlPK, DateienExportierenBackgroundServiceContext context) {
    Wahl wahl = findeWahl(wahlPK);
    if (wahl == null) {
      LOG.warn("Wahl nicht gefunden: " + wahlPK);
      return false;
    }
    return exportiere(wahl, context);
  }

  public boolean exportiere(WahlterminPK wahlterminPK, DateienExportierenBackgroundServiceContext context) {
    Wahltermin wahltermin = findeWahltermin(wahlterminPK);
    if (wahltermin == null) {
      LOG.warn("Wahltermin nicht gefunden: " + wahlterminPK);
      return false;
    }
    return exportiere(wahltermin, context);
  }

  protected boolean exportiere(WahlOderWahltermin wahlOderWahltermin, DateienExportierenBackgroundServiceContext context) {
    try {
      File exportVerzeichnis = pruefeVerzeichnis(wahlOderWahltermin, context.getExportVerzeichnis());

      DateienExportierenBackgroundServiceExportContext exportContext = context.getExportContext();

      Wahl wahl = getWahl(wahlOderWahltermin);
      Wahltermin wahltermin = getWahltermin(wahlOderWahltermin);
      FileFormat fileFormat = bestimmeFileFormat(exportContext.getFormatResolvers(), wahltermin, wahl);

      LOG.info("Starte Export");
      DateiExportPK dateiExportPK = BeanManagerUtil.getBeanByClass(exportContext.getExporterClass()).export(fileFormat,
          exportContext.getContextFct().apply(wahlOderWahltermin), wahlOderWahltermin.getMandant(), wahl, wahltermin);

      LOG.info("Speichere Datei in Export-Verzeichnis");

      speichereInVerzeichnis(dateiExportPK, exportVerzeichnis);

    } catch (Exception e) {
      systemLogWriter.writeErrorLogMessageFuerMandant(wahlOderWahltermin, wahlOderWahltermin.getName() + " - " + e.getLocalizedMessage(), e,
          context.getSystemLogQuelle());
    }

    return false;

  }

  private void speichereInVerzeichnis(DateiExportPK dateiExportPK, File exportVerzeichnis) throws IOException {
    Datei datei = dateiExportDAO.findByPrimaryKey(dateiExportPK).getDatei();
    DefaultStreamedContent content = datei.getDefaultStreamedContent(streamCreator);
    FileUtils.copyInputStreamToFile(content.getStream(),
        new File(exportVerzeichnis.getAbsolutePath() + File.separator + content.getName()));
  }

  private FileFormat bestimmeFileFormat(Instance<? extends DateienImportExportFormatResolver> formatResolvers, Wahltermin wahltermin, Wahl wahl) {
    if (formatResolvers.isUnsatisfied()) {
      throw new DateienExchangeBackgroundServiceException("datei.exportieren.background.kein.unterstuetztes.format");
    }

    List<DateienImportExportFormatResolver> passendeResolver = new ArrayList<>();

    for (DateienImportExportFormatResolver formatResolver : formatResolvers) {
      if (formatResolver.isAccept(wahltermin, wahl)) {
        passendeResolver.add(formatResolver);
      }
    }

    if (passendeResolver.isEmpty()) {
      throw new DateienExchangeBackgroundServiceException("datei.exportieren.background.kein.unterstuetztes.format.wahltermin.wahl", wahltermin, wahl);
    }

    if (passendeResolver.size() > 1) {
      Set<String> formate = new HashSet<>();
      passendeResolver.forEach(r -> formate.add(r.getFormatName()));
      throw new DateienExchangeBackgroundServiceException("datei.exportieren.background.mehr.als.ein.unterstuetztes.format",
          String.join(", ", formate.stream().map(messages::getMessageForMessageKey).collect(toList())));
    }

    DateienImportExportFormatResolver passend = passendeResolver.get(0);
    return new FileFormat(passend.getFormatName(), passend.getFileType());
  }

  private Wahltermin getWahltermin(WahlOderWahltermin wahlOderWahltermin) {
    if (wahlOderWahltermin.isInstanceOfWahl()) {
      return wahlOderWahltermin.castTo(Wahl.class).getEntity().getWahltermin();
    }
    return wahlOderWahltermin.castTo(Wahltermin.class).getEntity();
  }

  private Wahl getWahl(WahlOderWahltermin wahlOderWahltermin) {
    if (wahlOderWahltermin.isInstanceOfWahl()) {
      return wahlOderWahltermin.castTo(Wahl.class).getEntity();
    }
    return null;
  }

}
