package com.airlock.iam.servicecontainer.app.infrastructure.fileloader;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.servicecontainer.app.domain.service.fileloader.FileService;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public final class RecursiveFileService implements FileService {
   private static final ELogger LOG = ELoggerFactory.getLogger(RecursiveFileService.class);
   private final File directory;
   private final Pattern filenameFilter;

   @Override
   public List<File> findFiles() {
      try (Stream<Path> stream = Files.walk(this.directory.toPath())) {
         try {
            List<File> files = stream.filter(x$0 -> Files.isRegularFile(x$0))
               .filter(path -> isMatchingRegexFilter(path, this.filenameFilter))
               .map(Path::toFile)
               .sorted()
               .toList();
            LOG.debug(String.format("Found %d matching files: %s", files.size(), files));
            return files;
         } catch (UncheckedIOException e) {
            throw e.getCause();
         }
      } catch (AccessDeniedException e) {
         throw new FailureException(String.format("Permission error while accessing: %s", e.getMessage()));
      } catch (IOException e) {
         throw new FailureException("Error while listing files: " + e.getMessage(), e);
      }
   }

   @Override
   public void deleteFile(File file) {
      try {
         Files.delete(file.toPath());
         LOG.info(String.format("File %s deleted", file));
      } catch (NoSuchFileException e) {
         throw new FailureException(String.format("Error while deleting nonexistent file %s", file));
      } catch (IOException e) {
         throw new FailureException(String.format("Error while deleting file %s: %s", file, e.getMessage()));
      }
   }

   private static boolean isMatchingRegexFilter(Path path, Pattern filenamePattern) {
      Path fileName = path.getFileName();
      return fileName == null ? false : filenamePattern.matcher(fileName.toString()).matches();
   }

   @SuppressFBWarnings(justification = "generated code")
   public RecursiveFileService(File directory, Pattern filenameFilter) {
      this.directory = directory;
      this.filenameFilter = filenameFilter;
   }
}
