package top.r3944realms.docchecktoolrefactored.cil;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.cli.*;
import top.r3944realms.docchecktoolrefactored.core.DuplicateFinder;
import top.r3944realms.docchecktoolrefactored.core.FileHashCalculator;
import top.r3944realms.docchecktoolrefactored.io.scanner.FileScanner;
import top.r3944realms.docchecktoolrefactored.io.scanner.RobustParallelScanner;
import top.r3944realms.docchecktoolrefactored.model.DuplicateGroup;
import top.r3944realms.docchecktoolrefactored.util.FileUtil;
import top.r3944realms.docchecktoolrefactored.util.LoggerMarker;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 命令行处理器，负责解析参数和执行重复文件检查
 */
@Slf4j
public class CliProcessor {
    // 参数定义
    private static final String HELP_OPTION = "h";
    private static final String DIRECTORY_OPTION = "d";
    private static final String PROGRESS_OPTION = "p";
    private static final String MIN_SIZE_OPTION = "m";
    private static final String MAX_SIZE_OPTION = "M";
    private static final String EXCLUDE_OPTION = "e";
    private static final String FORMAT_OPTION = "f";
    private static final String OUTPUT_OPTION = "o";
    private static final String QUIET_OPTION = "q";
    private static final String SORT_OPTION = "s";
    private static final String VERSION_OPTION = "v";

    // 支持的输出格式
    private enum OutputFormat {
        TEXT, JSON, CSV
    }

    // 支持的排序方式
    private enum SortBy {
        SIZE, COUNT, PATH
    }

    // 配置选项
    private boolean showProgress = false;
    private boolean quietMode = false;
    private OutputFormat outputFormat = OutputFormat.TEXT;
    private SortBy sortBy = SortBy.SIZE;
    private Path outputFile = null;
    private long minSize = 0;
    private Long maxSize = null;
    private List<String> excludeExtensions = List.of();

    /**
     * 处理命令行参数并执行相应操作
     * @param args 命令行参数
     */
    public void process(String[] args) {
        Options options = createOptions();
        CommandLineParser parser = new DefaultParser();

        try {
            CommandLine cmd = parser.parse(options, args);

            // 处理帮助选项
            if (cmd.hasOption(HELP_OPTION)) {
                printHelp(options);
                return;
            }

            // 处理版本选项
            if (cmd.hasOption(VERSION_OPTION)) {
                printVersion();
                return;
            }

            // 解析参数
            parseOptions(cmd);

            // 验证目录参数
            if (!cmd.hasOption(DIRECTORY_OPTION)) {
                throw new IllegalArgumentException("Directory option (-d) is required");
            }
            Path scanDir = Paths.get(cmd.getOptionValue(DIRECTORY_OPTION));

            // 执行扫描
            List<DuplicateGroup> duplicates = scanForDuplicates(scanDir);

            // 输出结果
            outputResults(duplicates);

        } catch (ParseException e) {
            System.err.println("Error: " + e.getMessage());
            printHelp(options);
            System.exit(1);
        } catch (Exception e) {
            log.error(LoggerMarker.DEBUG_MARKER, "Error processing CLI command", e);
            System.err.println("Error: " + e.getMessage());
            System.exit(1);
        }
    }

    /**
     * 创建命令行选项
     */
    private Options createOptions() {
        Options options = new Options();

        // 基本选项
        options.addOption(Option.builder(HELP_OPTION)
                .longOpt("help")
                .desc("Show this help message")
                .build());
        options.addOption(Option.builder(VERSION_OPTION)
                .longOpt("version")
                .desc("Show version information")
                .build());
        options.addOption(Option.builder(DIRECTORY_OPTION)
                .longOpt("directory")
                .hasArg()
                .argName("PATH")
                .desc("Directory to scan for duplicates")
                .build());
        options.addOption(Option.builder(PROGRESS_OPTION)
                .longOpt("progress")
                .desc("Show progress bar during processing")
                .build());
        options.addOption(Option.builder(QUIET_OPTION)
                .longOpt("quiet")
                .desc("Quiet mode, only show errors")
                .build());

        // 过滤选项
        options.addOption(Option.builder(MIN_SIZE_OPTION)
                .longOpt("min-size")
                .hasArg()
                .argName("BYTES")
                .desc("Minimum file size to consider (in bytes)")
                .build());
        options.addOption(Option.builder(MAX_SIZE_OPTION)
                .longOpt("max-size")
                .hasArg()
                .argName("BYTES")
                .desc("Maximum file size to consider (in bytes)")
                .build());
        options.addOption(Option.builder(EXCLUDE_OPTION)
                .longOpt("exclude")
                .hasArg()
                .argName("EXTENSIONS")
                .desc("Comma-separated list of file extensions to exclude")
                .build());

        // 输出控制选项
        options.addOption(Option.builder(FORMAT_OPTION)
                .longOpt("format")
                .hasArg()
                .argName("FORMAT")
                .desc("Output format (text/json/csv), default: text")
                .build());
        options.addOption(Option.builder(OUTPUT_OPTION)
                .longOpt("output")
                .hasArg()
                .argName("FILE")
                .desc("Write output to file instead of stdout")
                .build());
        options.addOption(Option.builder(SORT_OPTION)
                .longOpt("sort")
                .hasArg()
                .argName("CRITERIA")
                .desc("Sort results by (size/count/path), default: size")
                .build());

        return options;
    }

    /**
     * 解析命令行选项
     */
    private void parseOptions(CommandLine cmd) throws ParseException {
        showProgress = cmd.hasOption(PROGRESS_OPTION);
        quietMode = cmd.hasOption(QUIET_OPTION);

        // 解析输出格式
        if (cmd.hasOption(FORMAT_OPTION)) {
            try {
                outputFormat = OutputFormat.valueOf(cmd.getOptionValue(FORMAT_OPTION).toUpperCase());
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException("Invalid output format. Allowed values: text, json, csv");
            }
        }

        // 解析排序方式
        if (cmd.hasOption(SORT_OPTION)) {
            try {
                sortBy = SortBy.valueOf(cmd.getOptionValue(SORT_OPTION).toUpperCase());
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException("Invalid sort criteria. Allowed values: size, count, path");
            }
        }

        // 解析输出文件
        if (cmd.hasOption(OUTPUT_OPTION)) {
            outputFile = Paths.get(cmd.getOptionValue(OUTPUT_OPTION));
        }

        // 解析大小限制
        if (cmd.hasOption(MIN_SIZE_OPTION)) {
            try {
                minSize = Long.parseLong(cmd.getOptionValue(MIN_SIZE_OPTION));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid min-size value: must be a number");
            }
        }

        if (cmd.hasOption(MAX_SIZE_OPTION)) {
            try {
                maxSize = Long.parseLong(cmd.getOptionValue(MAX_SIZE_OPTION));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid max-size value: must be a number");
            }
        }

        // 解析排除的扩展名
        if (cmd.hasOption(EXCLUDE_OPTION)) {
            excludeExtensions = Arrays.asList(cmd.getOptionValue(EXCLUDE_OPTION).split(","));
        }
    }

    /**
     * 执行重复文件扫描
     */
    private List<DuplicateGroup> scanForDuplicates(Path scanDir) throws IOException {
        if (!quietMode) {
            System.out.println("Scanning directory: " + scanDir.toAbsolutePath());
        }

        FileScanner scanner = new RobustParallelScanner(20);
        FileHashCalculator calculator = FileHashCalculator.defaultInstance();
        DuplicateFinder finder = new DuplicateFinder(scanner, calculator, showProgress);

        List<DuplicateGroup> duplicates = finder.findDuplicates(scanDir);

        // 应用过滤
        duplicates = filterResults(duplicates);

        // 应用排序
        duplicates = sortResults(duplicates);

        return duplicates;
    }

    /**
     * 过滤结果
     */
    private List<DuplicateGroup> filterResults(List<DuplicateGroup> groups) {
        return groups.stream()
                .filter(group -> group.size() >= minSize)
                .filter(group -> maxSize == null || group.size() <= maxSize)
                .filter(group -> excludeExtensions.stream()
                        .noneMatch(ext -> group.fileMetas().stream()
                                .anyMatch(file -> file.getPath().toString().toLowerCase().endsWith(ext.toLowerCase()))))
                .collect(Collectors.toList());
    }

    /**
     * 排序结果
     */
    private List<DuplicateGroup> sortResults(List<DuplicateGroup> groups) {
        return switch (sortBy) {
            case SIZE -> groups.stream()
                    .sorted((g1, g2) -> Long.compare(g2.size(), g1.size()))
                    .collect(Collectors.toList());
            case COUNT -> groups.stream()
                    .sorted((g1, g2) -> Integer.compare(g2.fileMetas().size(), g1.fileMetas().size()))
                    .collect(Collectors.toList());
            case PATH -> groups.stream()
                    .sorted(Comparator.comparing(g -> g.fileMetas().get(0).getPath()))
                    .collect(Collectors.toList());
        };
    }

    /**
     * 输出结果
     */
    private void outputResults(List<DuplicateGroup> duplicates) throws IOException {
        if (quietMode && duplicates.isEmpty()) {
            return;
        }

        String outputContent = switch (outputFormat) {
            case JSON -> formatAsJson(duplicates);
            case CSV -> formatAsCsv(duplicates);
            default -> formatAsText(duplicates);
        };

        if (outputFile != null) {
            try (BufferedWriter writer = Files.newBufferedWriter(outputFile)) {
                writer.write(outputContent);
            }
            if (!quietMode) {
                System.out.println("Results written to: " + outputFile.toAbsolutePath());
            }
        } else {
            System.out.println(outputContent);
        }
    }

    /**
     * 文本格式输出
     */
    private String formatAsText(List<DuplicateGroup> duplicates) {
        if (duplicates.isEmpty()) {
            return "No duplicate files found.";
        }

        StringBuilder sb = new StringBuilder();
        sb.append(String.format("\nFound %d groups of duplicate files:\n", duplicates.size()));

        AtomicInteger groupNum = new AtomicInteger(1);
        duplicates.forEach(group -> {
            sb.append(String.format("\nGroup %d:\n", groupNum.getAndIncrement()));
            sb.append(String.format("Hash: %s\n", group.hash()));
            sb.append(String.format("Size: %s\n", FileUtil.humanReadableByteCount(group.size())));
            sb.append("Files:\n");
            group.fileMetas().forEach(file -> sb.append(String.format("  %s\n", file.getPath())));
        });

        // 添加统计信息
        long totalWastedSpace = duplicates.stream()
                .mapToLong(group -> group.size() * (group.fileMetas().size() - 1))
                .sum();
        sb.append(String.format("\nTotal wasted space: %s\n",
                FileUtil.humanReadableByteCount(totalWastedSpace)));

        return sb.toString();
    }

    /**
     * JSON格式输出
     */
    private String formatAsJson(List<DuplicateGroup> duplicates) {
        StringBuilder sb = new StringBuilder();
        sb.append("{\n");

        // 基本信息
        sb.append("  \"duplicate_groups\": [\n");

        // 各组数据
        duplicates.forEach(group -> {
            sb.append("    {\n");
            sb.append(String.format("      \"hash\": \"%s\",\n", group.hash()));
            sb.append(String.format("      \"size\": %d,\n", group.size()));
            sb.append(String.format("      \"size_human\": \"%s\",\n",
                    FileUtil.humanReadableByteCount(group.size())));
            sb.append("      \"files\": [\n");

            group.fileMetas().forEach(file ->
                    sb.append(String.format("        \"%s\",\n", file.getPath())));

            // 移除最后一个逗号
            if (!group.fileMetas().isEmpty()) {
                sb.delete(sb.length() - 2, sb.length());
                sb.append("\n");
            }

            sb.append("      ]\n");
            sb.append("    },\n");
        });

        // 移除最后一个逗号
        if (!duplicates.isEmpty()) {
            sb.delete(sb.length() - 2, sb.length());
            sb.append("\n");
        }

        sb.append("  ],\n");

        // 统计信息
        long totalWastedSpace = duplicates.stream()
                .mapToLong(group -> group.size() * (group.fileMetas().size() - 1))
                .sum();
        sb.append("  \"stats\": {\n");
        sb.append(String.format("    \"total_groups\": %d,\n", duplicates.size()));
        sb.append(String.format("    \"total_files\": %d,\n",
                duplicates.stream().mapToInt(group -> group.fileMetas().size()).sum()));
        sb.append(String.format("    \"total_wasted_space\": %d,\n", totalWastedSpace));
        sb.append(String.format("    \"total_wasted_space_human\": \"%s\"\n",
                FileUtil.humanReadableByteCount(totalWastedSpace)));
        sb.append("  }\n");

        sb.append("}\n");
        return sb.toString();
    }

    /**
     * CSV格式输出
     */
    private String formatAsCsv(List<DuplicateGroup> duplicates) {
        StringBuilder sb = new StringBuilder();
        sb.append("group,hash,size,size_human,file_path\n");

        AtomicInteger groupNum = new AtomicInteger(1);
        duplicates.forEach(group -> {
            String groupPrefix = groupNum.getAndIncrement() + "," +
                    group.hash() + "," +
                    group.size() + "," +
                    FileUtil.humanReadableByteCount(group.size());

            group.fileMetas().forEach(file ->
                    sb.append(groupPrefix).append(",").append(file.getPath()).append("\n"));
        });

        return sb.toString();
    }

    /**
     * 打印帮助信息
     */
    private void printHelp(Options options) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("doc-check-tool", options);
    }

    /**
     * 打印版本信息
     */
    private void printVersion() {
        Package pkg = getClass().getPackage();
        String version = pkg.getImplementationVersion();
        System.out.println("Doc Check Tool " + (version != null ? version : "DEV"));
    }
}