package de.ivu.elect.was.exchange;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.annotation.Nonnull;
import javax.inject.Inject;

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

import de.ivu.elect.business.konfiguration.entity.ElectKonfigurationWerte;
import de.ivu.elect.business.konfiguration.entity.KonfigurationLoader;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.replikation.entity.FileInfo;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.util.FileUtil;


import static de.ivu.elect.business.system.entity.SystemLogQuelle.AUTOMATISCHER_DATEI_IMPORT;
import static java.util.stream.Collectors.toList;

/**
 *  on 17.11.2015.
 */
public abstract class AbstractDateienAutomatischImporteren<FI extends FileInfo> {

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

  @Inject
  protected transient KonfigurationLoader konfigurationLoader;

  @Inject
  protected transient SystemLogWriter systemLogWriter;

  @Inject
  private transient DateienAutomatischImportierenImportDeaktivieren dateienAutomatischImportierenImportDeaktivieren;

  public void importiere(Mandant mandant) {
    long start = System.currentTimeMillis();
    try {
      List<FI> dateien = bestimmeZuImportierendeDateien();

      if (dateien.isEmpty()) {
        getLog().info("Nichts zu importieren");
        return;
      }

      dateienVorImport(dateien);

      int count = 0;
      for (FI fi : dateien) {
        count++;
        if (count > getMaxAnzahlDateienProTransaktion()) {
          getLog().info("Commit, weiter in nächster Transaktion, Dauer dieses Durchlaufs in ms: " + (System.currentTimeMillis()-start));
          break;
        }

        try {
          importiereDatei(mandant, fi);
          afterImportSuccess(fi);
        } catch (Exception e) {
          systemLogWriter.writeErrorLogMessageFuerMandant(mandant, getImporterName() + ": Fehler bei Datei:'" + fi + "'", e, AUTOMATISCHER_DATEI_IMPORT);
          try {
            if (handleFehlerInDatei(fi)) {
              systemLogWriter.writeErrorLogMessageFuerMandant(mandant, getImporterName() + ": Import deaktiviert, Fehler bei Datei:'" + fi + "'", AUTOMATISCHER_DATEI_IMPORT);
              deaktiviereImport();
            }
          } catch (Exception ee) {
            systemLogWriter.writeErrorLogMessageFuerMandant(mandant, getImporterName() + ": Import deaktiviert, Fehler bei Datei:'" + fi + "'", ee, AUTOMATISCHER_DATEI_IMPORT);
            deaktiviereImport();
          }
        }
      }
    } catch (Exception e) {
      systemLogWriter.writeErrorLogMessageNewTransaction(getImporterName() + ": Import deaktiviert", e, AUTOMATISCHER_DATEI_IMPORT);
      deaktiviereImport();
    }
  }

  protected abstract void afterImportSuccess(FI fi) throws Exception;

  /**
   * true, wenn Import deaktiviert werden soll...
   */
  protected abstract boolean handleFehlerInDatei(FI fi) throws Exception;

  protected abstract List<FI> bestimmeZuImportierendeDateien();

  protected void dateienVorImport(List<FI> dateien) throws Exception {
    // nichts zu tun
  }

  protected void deaktiviereImport() {
    dateienAutomatischImportierenImportDeaktivieren.deaktiviereImport(getCronTabKonfigurationWert());
  }

  protected abstract void importiereDatei(Mandant mandant, FI fi) throws Exception;

  protected abstract int getMaxAnzahlDateienProTransaktion();

  protected boolean isDateiFuerImportVorhanden() {
    List<FI> files = bestimmeZuImportierendeDateien();
    getLog().info("Dateien zum Import: " + files.size());
    return !files.isEmpty();
  }

  protected abstract Logger getLog();

  protected List<File> alleDateienInVerzeichnis(File verzeichnis, boolean recursive) {
    try {
      return FileUtil.listFilesInDirectoryFast(verzeichnis, recursive).stream().filter(this::isFormatDateinameGueltig).collect(toList());
    } catch (IOException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  protected abstract String getFormatMessage();

  protected abstract boolean isFormatDateinameGueltig(File file);

  protected boolean isDeaktiviert() {
    return StringUtils.isBlank(konfigurationLoader.resolveStringValue(getCronTabKonfigurationWert()));
  }

  @Nonnull
  protected abstract ElectKonfigurationWerte getCronTabKonfigurationWert();

  protected abstract String getImporterName();




}
