package de.ivu.elect.business.system.control.files.strategies;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.datei.boundary.DateiDAO;
import de.ivu.elect.business.konfiguration.entity.ElectKonfigurationWerte;
import de.ivu.elect.business.konfiguration.entity.KonfigurationLoader;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.business.system.entity.SystemLogQuelle;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.util.FileUtil;


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

public class DateiInDatenbankGeloeschtFileCleanUpStrategy extends AbstractFileCleanupStrategy implements FileCleanupStrategy {

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

  private static final long DATEIEN_PRO_DURCHLAUF = 1000;


  public static final Set<String> DENYLIST = new HashSet<>();

  @Inject
  private transient DateiDAO dateiDAO;

  @Inject
  private transient SystemLogWriter systemLogWriter;

  @Inject
  private transient Messages messages;

  @Inject
  private transient KonfigurationLoader konfigurationLoader;

  @Override
  protected Logger getLog() {
    return LOG;
  }

  @Override
  public boolean isDirtyFilePresent(File verzeichnis) throws IOException {
    return !getZuBereinigendeDateien(verzeichnis).isEmpty();
  }

  @Override
  public void bereinige(File verzeichnis) throws Exception {
    long count = 0;
    for (File file : getZuBereinigendeDateien(verzeichnis)) {
      count++;
      if (count > DATEIEN_PRO_DURCHLAUF) {
        return;
      }
      bereinige(verzeichnis, file);
    }
  }

  @Override
  public String getName() {
    return DateiInDatenbankGeloeschtFileCleanUpStrategy.class.getName();
  }

  private void bereinige(File verzeichnis, File file) {
    try {
      verschiebeInRecycleBin(file, verzeichnis);
    } catch (Exception e){
      // ELECT-8678
      DENYLIST.add(file.getName());
      systemLogWriter.writeWarnLogMessageFuerSystemMandant(messages.getMessageForMessageKey("datei.cleanup.move.recycle.failed", file.getName()),e, SystemLogQuelle.FILE_CLEANUP);
    }

  }

  private Collection<File> getZuBereinigendeDateien(File verzeichnis) throws IOException {
    getLog().info("Lade bekannte Dateinamen");
    Set<String> knownFileNames = new HashSet<>(dateiDAO.findByAllDateinamen());
    getLog().info("Lade bekannte Dateinamen - done, habe: " + knownFileNames.size());

    Long minimaleZeit = konfigurationLoader.resolveLongValueOptional(ElectKonfigurationWerte.ELECT_COMMON_DATEI_CLEANUP_MS_BEFORE_RECYLE);
    long now = System.currentTimeMillis();
    LOG.info("Minimale Zeit: " + minimaleZeit);

    return FileUtil.listFilesInDirectoryFast(verzeichnis, true).stream()
        // nicht notwendig .filter(File::isFile)
        .filter(f -> !DENYLIST.contains(f.getName())) // ELECT-8678
        .filter(f -> !knownFileNames.contains(f.getName()))
        .filter(f -> !isInRecycleBin(f))
        .filter(f -> isAusreichendAlt(f, minimaleZeit, now))
        .collect(toList());
  }

  private boolean isAusreichendAlt(File f, Long minimaleZeit, long now) {
    if (minimaleZeit == null || minimaleZeit <= 0L) {
      return true;
    }
    return now - f.lastModified() >= minimaleZeit;
  }

}
