package ru.soune.nocopy.service.file;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ru.soune.nocopy.entity.user.ProtectedFileCheck;
import ru.soune.nocopy.repository.ProtectedFileCheckRepository;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
@RequiredArgsConstructor
public class FileCleanupService {

    @Value("${file.storage.base-path}")
    private String basePath;

    @Value("${file.storage.temp-ttl-hours}")
    private int tempTtlHours;

    private final ProtectedFileCheckRepository protectedFileCheckRepository;

    @Scheduled(cron = "0 0 3 * * *")
    public void cleanupExpiredFiles() {
        log.info("Starting cleanup of expired temporary files");

        cleanupTempFilesNightly();

        Path tempDir = Paths.get(basePath, "temp");
        if (!Files.exists(tempDir)) {
            return;
        }

        try {
            Files.walkFileTree(tempDir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {

                    LocalDateTime fileTime = LocalDateTime.ofInstant(
                            Instant.ofEpochMilli(attrs.lastModifiedTime().toMillis()),
                            ZoneId.systemDefault()
                    );

                    LocalDateTime cutoffTime = LocalDateTime.now()
                            .minusHours(tempTtlHours);

                    if (fileTime.isBefore(cutoffTime)) {
                        Files.delete(file);
                        log.debug("Deleted expired file: {}", file);
                    }

                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                        throws IOException {

                    if (exc == null) {
                        if (Files.list(dir).count() == 0 &&
                                !dir.equals(tempDir)) {
                            Files.delete(dir);
                            log.debug("Deleted empty directory: {}", dir);
                        }
                    }

                    return FileVisitResult.CONTINUE;
                }
            });

            log.info("Cleanup completed successfully");

        } catch (IOException e) {
            log.error("Error during cleanup", e);
        }
    }

    private void cleanupTempFilesNightly() {
        log.info("Starting nightly cleanup of temporary files");

        String tempDir = System.getProperty("java.io.tmpdir");
        Path tempPath = Paths.get(tempDir);

        if (!Files.exists(tempPath)) {
            return;
        }

        Instant cutoffTime = Instant.now().minus(24, ChronoUnit.HOURS); // 24 часа
        int deletedCount = 0;

        try (Stream<Path> files = Files.list(tempPath)) {
            List<Path> tempFiles = files
                    .filter(path -> {
                        String filename = path.getFileName().toString();
                        return filename.contains("_") &&
                                !filename.endsWith(".tmp") &&
                                Files.isRegularFile(path);
                    })
                    .collect(Collectors.toList());

            for (Path filePath : tempFiles) {
                try {
                    File file = filePath.toFile();
                    Instant lastModified = Instant.ofEpochMilli(file.lastModified());

                    if (lastModified.isBefore(cutoffTime)) {
                        boolean deleted = Files.deleteIfExists(filePath);
                        if (deleted) {
                            deletedCount++;
                        }
                    }
                } catch (IOException e) {
                    log.error("Error deleting file: {}", filePath, e);
                }
            }

            log.info("Nightly cleanup deleted {} temporary files", deletedCount);

        } catch (IOException e) {
            log.error("Failed to list temp directory", e);
        }
    }
}
