package top.r3944realms.docchecktoolrefactored.core;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import top.r3944realms.docchecktoolrefactored.System;
import top.r3944realms.docchecktoolrefactored.ThreadPoolManager;
import top.r3944realms.docchecktoolrefactored.io.scanner.FileScanner;
import top.r3944realms.docchecktoolrefactored.io.scanner.RobustParallelScanner;
import top.r3944realms.docchecktoolrefactored.util.LoggerMarker;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Setter
@Slf4j
public class HashFileGenerator {
    private ProgressCallback callback;
    private final FileHashCalculator hashCalculator;

    public HashFileGenerator() {
        this.hashCalculator = FileHashCalculator.defaultInstance();
    }

    public HashFileGenerator(FileHashCalculator hashCalculator) {
        this.hashCalculator = hashCalculator;
    }

    public interface ProgressCallback {
        void onProgressUpdate(int current, int total);
    }

    private void safeOnProgressUpdate(int current, int total) {
        if (callback != null) {
            callback.onProgressUpdate(current, total);
        }
    }

    public void generateHashFile(List<Path> directories, Path outputFile)
            throws IOException, InterruptedException {

        // 开始时检查中断
        if (Thread.interrupted()) {
            throw new InterruptedException("任务被取消");
        }

        List<Path> allFiles = new ArrayList<>();

        // 扫描所有目录中的文件
        for (Path directory : directories) {
            if (Thread.interrupted()) {
                throw new InterruptedException("任务被取消");
            }

            if (!Files.isDirectory(directory)) {
                throw new IllegalArgumentException("指定路径不是有效目录: " + directory);
            }

            List<Path> files = new ArrayList<>();
            CompletableFuture<Void> scanFuture = new CompletableFuture<>();

            // 使用 RobustParallelScanner 扫描文件
            try (RobustParallelScanner scanner = new RobustParallelScanner(10)) {
                scanner.scan(directory, new FileScanner.FileScanListener() {
                    @Override
                    public void onFileFound(Path file) {
                        files.add(file);
                    }

                    @Override
                    public void onScanComplete() {
                        scanFuture.complete(null);
                    }

                    @Override
                    public void onError(Path path, Exception e) {
                        log.error(LoggerMarker.TRACE_MARKER, "扫描错误: {} - {}", path, e.getMessage());
                    }
                });

                // 使用带超时的等待，并响应中断
                try {
                    scanFuture.get(System.getSetting().getScanTimeout(), TimeUnit.SECONDS); // 设置合理的超时时间
                } catch (TimeoutException e) {
                    throw new IOException("扫描超时: " + directory, e);
                } catch (ExecutionException e) {
                    throw new IOException("扫描失败: " + directory, e);
                }

                allFiles.addAll(files);
            }
        }

        // 检查是否被中断
        if (Thread.interrupted()) {
            throw new InterruptedException("任务被取消");
        }

        // 计算每个文件的哈希值
        List<String[]> hashResults = new ArrayList<>();
        AtomicInteger processedFiles = new AtomicInteger(0);
        int totalFiles = allFiles.size();

        processFilesInParallel(allFiles, hashResults, processedFiles, totalFiles);

        // 检查是否被中断
        if (Thread.interrupted()) {
            throw new InterruptedException("任务被取消");
        }

        // 写入结果到文件
        writeResultsToFile(outputFile, hashResults);
    }

    private void processFilesInParallel(List<Path> files, List<String[]> results,
                                        AtomicInteger processedFiles, int totalFiles)
            throws InterruptedException {

        int processors = Runtime.getRuntime().availableProcessors();
        ExecutorService executor = ThreadPoolManager.createPool("hash-generator", Runtime.getRuntime().availableProcessors());

        try {
            CountDownLatch latch = new CountDownLatch(files.size());

            for (Path file : files) {
                executor.submit(() -> {
                    try {
                        // 检查中断
                        if (Thread.interrupted()) {
                            return;
                        }

                        String hash = hashCalculator.calculateHash(file);
                        String[] result = {file.getFileName().toString(), hash};

                        synchronized (results) {
                            results.add(result);
                        }

                        int processed = processedFiles.incrementAndGet();
                        safeOnProgressUpdate(processed, totalFiles);

                    } catch (IOException e) {
                        log.error(LoggerMarker.DEBUG_MARKER, "无法计算文件哈希值: {} - {}", file, e.getMessage());
                    } finally {
                        latch.countDown();
                    }
                });
            }

            // 等待所有任务完成，但响应中断
            while (!latch.await(100, TimeUnit.MILLISECONDS)) {
                if (Thread.interrupted()) {
                    throw new InterruptedException("哈希计算被取消");
                }
            }

        } finally {
            executor.shutdownNow();
        }
    }

    private void writeResultsToFile(Path outputFile, List<String[]> results)
            throws IOException, InterruptedException {

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile.toFile()))) {
            writer.write("文件名,哈希值");
            writer.newLine();

            for (String[] result : results) {
                // 检查中断
                if (Thread.interrupted()) {
                    throw new InterruptedException("文件写入被取消");
                }

                writer.write(result[0] + "," + result[1]);
                writer.newLine();

                // 每写入100行检查一次中断，减少检查频率
                if (results.indexOf(result) % 100 == 0) {
                    if (Thread.interrupted()) {
                        throw new InterruptedException("文件写入被取消");
                    }
                }
            }
        }
    }
}