package top.r3944realms.docchecktoolrefactored.ui.module;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.FileChooser;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.docchecktoolrefactored.System;
import top.r3944realms.docchecktoolrefactored.core.AddressFileComparator;
import top.r3944realms.docchecktoolrefactored.core.AddressFileGenerator;
import top.r3944realms.docchecktoolrefactored.ui.SceneManager;
import top.r3944realms.docchecktoolrefactored.ui.task.AddressFileComparisonTask;
import top.r3944realms.docchecktoolrefactored.ui.task.AddressFileGenerationTask;
import top.r3944realms.docchecktoolrefactored.ui.utils.DialogUtil;
import top.r3944realms.docchecktoolrefactored.ui.utils.ProgressBar;
import top.r3944realms.docchecktoolrefactored.util.LoggerMarker;

import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;


/**
 * The type Path check pane controller.
 */
@Slf4j
public class PathCheckPaneController implements Initializable {
    @FXML private ChoiceBox<Mode> loadFolderType2CB;
    @FXML private TextArea result2TA;
    @FXML private Button start2B;
    @FXML private TextField loadCatalog2TF;
    @FXML private TextField loadJPGFolder2TF;
    @FXML private Button selectLoadCatalog2B;
    @FXML private Button selectJPGFolder2B;
    @FXML private Button generateLogicalAddress2B;
    @FXML private Button generatePhysicalAddress2B;
    // 存储生成的文件路径
    private String logicalAddressFilePath = null;
    private String physicalAddressFilePath = null;


    private final ProgressBar progressBar = new ProgressBar(false);
    private final ProgressBar cancelableProgressBar = new ProgressBar();
    private Task<?> currentTask; // 保存任务引用
    /**
     * On select lc.
     *
     * @param actionEvent the action event
     */
    @FXML void onSelectLC(ActionEvent actionEvent) {
        log.info(LoggerMarker.DEBUG_MARKER, "用户点击了选择目录文件按钮");
        FileChooser fileChooser = System.getFileChooser();
        fileChooser.setTitle("选择目录文件");

        // 设置文件过滤器，只允许DBF、XML、xlsx、xls格式

        FileChooser.ExtensionFilter xlsxFilter = new FileChooser.ExtensionFilter("Excel Files (*.xlsx)", "*.xlsx");
        FileChooser.ExtensionFilter xlsFilter = new FileChooser.ExtensionFilter("Excel Files (*.xls)", "*.xls");
        FileChooser.ExtensionFilter dbfFilter = new FileChooser.ExtensionFilter("DBF Files (*.dbf)", "*.dbf");
        FileChooser.ExtensionFilter xmlFilter = new FileChooser.ExtensionFilter("XML Files (*.xml)", "*.xml");

        fileChooser.getExtensionFilters().addAll(xlsxFilter, xlsFilter,dbfFilter, xmlFilter);

        // 显示文件选择对话框
        File selectedFile = fileChooser.showOpenDialog(selectLoadCatalog2B.getScene().getWindow());

        // 如果选择了文件，则将文件路径显示在loadCatalog2TF上
        if (selectedFile != null) {
            loadCatalog2TF.setText(selectedFile.getAbsolutePath());
            System.setLastModifiedFile(selectedFile);
            log.info(LoggerMarker.DEBUG_MARKER, "选择的目录文件路径为：{}", selectedFile.getAbsolutePath());
        } else {
            log.warn(LoggerMarker.DEBUG_MARKER, "用户未选择任何文件");
            DialogUtil.showWarningDialog("警告", "操作有误", "未选择任何文件夹，请重新选择");
            result2TA.setText("未选择载入目录文件，请重新选择。");
        }
    }

    /**
     * On select jpgf.
     *
     * @param actionEvent the action event
     */
    @FXML void onSelectJPGF(ActionEvent actionEvent) {
        javafx.stage.DirectoryChooser directoryChooser = System.getDirectoryChooser();
        // 正确获取当前选中的值
        Mode selectedMode = loadFolderType2CB.getValue();
        if (selectedMode == Mode.PAGE_TYPE) {
            directoryChooser.setTitle("选择页面级文件夹");
        } else if (selectedMode == Mode.FILE_TYPE) {
            directoryChooser.setTitle("选择文件级文件夹");
        }
        log.info(LoggerMarker.DEBUG_MARKER, "用户选择的模式为：{}", selectedMode);

        File selectedDirectory = directoryChooser.showDialog(selectJPGFolder2B.getScene().getWindow());

        if (selectedDirectory != null) {
            loadJPGFolder2TF.setText(selectedDirectory.getAbsolutePath());
            log.info(LoggerMarker.DEBUG_MARKER, "选择的{}文件夹路径为：{}", selectedMode,selectedDirectory.getAbsolutePath());
        } else {
            log.warn(LoggerMarker.DEBUG_MARKER, "用户未选择任何文件夹");
            DialogUtil.showWarningDialog("警告", "操作有误", "未选择任何文件夹，请重新选择");
            result2TA.setText("未选择载入文件夹，请重新选择。");
        }
        System.setLastModifiedFile(selectedDirectory);
    }

    /**
     * On generate la.
     *
     * @param actionEvent the action event
     */
    @FXML void onGenerateLA(ActionEvent actionEvent) {
        generateLogicalAddress2B.setDisable(true);
        removeResultStyle();
        log.info(LoggerMarker.DEBUG_MARKER, "用户点击了生成逻辑地址文件按钮");
        String filePath = loadCatalog2TF.getText();
        if (filePath.isEmpty()) {
            result2TA.setText("请先选择目录文件。");
            DialogUtil.showWarningDialog("警告", "操作有误", "请先选择目录文件");
            log.warn(LoggerMarker.DEBUG_MARKER, "未选择目录文件");
            generateLogicalAddress2B.setDisable(false);
            return;
        }

        Mode selectedMode = loadFolderType2CB.getValue();
        FileChooser fileChooser = System.getFileChooser();
        fileChooser.setTitle("选择保存逻辑地址文件的位置");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("CSV Files", "*.csv"));
        fileChooser.setInitialFileName(System.getProjectInfo().makeProjectInfoIntoFileNamePrefix() + "-" + selectedMode.toString() + "-逻辑地址文件 " + ".csv");

        File outputFile = fileChooser.showSaveDialog(generateLogicalAddress2B.getScene().getWindow());
        if (outputFile == null) {
            result2TA.setText("未选择保存位置");
            log.warn(LoggerMarker.DEBUG_MARKER, "用户未选择任何文件");
            DialogUtil.showWarningDialog("警告", "操作有误", "未选择保存位置");
            generateLogicalAddress2B.setDisable(false);
            return;
        }
        System.setLastModifiedFile(outputFile);
        progressBar.showProgress(SceneManager.getPrimaryStage(), "生成逻辑路径文件", "正在初始化...");
        // 正确处理文件扩展名 - 只有在没有.csv扩展名时才添加
        final File finalOutputFile;
        if (!outputFile.getName().toLowerCase().endsWith(".csv")) {
            finalOutputFile = new File(outputFile.getAbsolutePath() + ".csv");
        } else {
            finalOutputFile = outputFile;
        }

        // 保存生成的文件路径
        logicalAddressFilePath = finalOutputFile.getAbsolutePath();
        log.info(LoggerMarker.DEBUG_MARKER, "选择的输出文件路径: {}", logicalAddressFilePath);

        // 创建后台任务
        AddressFileGenerationTask task = new AddressFileGenerationTask(filePath, outputFile, selectedMode.number, true);
        // 绑定任务属性到UI
        ChangeListener<Number> progressChangeListener = (obs, oldVal, newVal) -> {
            if (newVal != null) {
                if (task.getMessage() != null) {
                    progressBar.updateProgress(newVal.doubleValue(), task.getMessage());
                }
            }
        };
        task.progressProperty().addListener(progressChangeListener);

        // 绑定任务的消息到结果文本区域
        ChangeListener<String> messageChangeListener = (observable, oldValue, newValue) -> {
            result2TA.setText(newValue);
        };
        task.messageProperty().addListener(messageChangeListener);
        // 当任务完成时显示完整结果
        task.setOnSucceeded(e -> {
            progressBar.closeProgress();
            result2TA.setText("生成逻辑路径 csv 文件任务完成，输出csv文件路径："+task.getValue());
            generateLogicalAddress2B.setDisable(false);
            addResultSuccessfulStyle();
            log.info(LoggerMarker.RELEASE_MARKER, "生成逻辑路径 csv 文件任务完成，输出csv文件路径：{}", task.getValue());
        });

        // 处理任务失败情况
        task.setOnFailed(e -> {
            progressBar.closeProgress();
            Throwable exception = task.getException();

            // 移除监听器时使用 task 而不是 currentTask
            task.progressProperty().removeListener(progressChangeListener);
            task.messageProperty().removeListener(messageChangeListener);

            // 检查是否是重复档号的特殊信息
            if (exception.getMessage() != null && exception.getMessage().startsWith("存在重复档号：")) {
                result2TA.setText(exception.getMessage());
            } else {
                result2TA.setText("检测过程中发生错误: " + exception.getMessage());
            }

            addResultErrorStyle();
            DialogUtil.showDetailedErrorDialog("错误", "检测过程中发生错误: ", exception.getMessage());
            generateLogicalAddress2B.setDisable(false);
            log.error(LoggerMarker.RELEASE_MARKER, "生成逻辑路径 csv 文件任务失败", exception);
        });

        // 处理任务取消情况
        task.setOnCancelled(e -> {
            progressBar.closeProgress();
            currentTask.progressProperty().removeListener(progressChangeListener);
            currentTask.messageProperty().removeListener(messageChangeListener);
            result2TA.appendText("\n检测已取消");
            removeResultStyle();
            generateLogicalAddress2B.setDisable(false);
            log.info(LoggerMarker.RELEASE_MARKER, "生成逻辑路径 csv 文件任务已被取消");
        });
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

    /**
     * On generate pa.
     *
     * @param actionEvent the action event
     */
    @FXML void onGeneratePA(ActionEvent actionEvent) {

        generatePhysicalAddress2B.setDisable(true);
        removeResultStyle();
        String folderPath = loadJPGFolder2TF.getText();
        if (folderPath.isEmpty()) {
            result2TA.setText("请先选择文件夹。");
            log.warn(LoggerMarker.DEBUG_MARKER, "请先选择文件夹");
            DialogUtil.showWarningDialog("警告", "操作有误", "请先选择文件夹");
            generatePhysicalAddress2B.setDisable(false);
            return;
        }
        File folder = new File(folderPath);
        if(!folder.exists() || !folder.isDirectory()) {
            result2TA.setText("所选路径不存在或不是一个有效的文件夹。");
            DialogUtil.showWarningDialog("警告", "操作有误", "所选路径不存在或不是一个有效的文件夹");
            log.warn(LoggerMarker.DEBUG_MARKER, "所选路径不存在或不是一个有效的文件夹");
            generatePhysicalAddress2B.setDisable(false);
            return;
        }
        Mode selectedMode = loadFolderType2CB.getValue();
        FileChooser fileChooser = System.getFileChooser();
        fileChooser.setTitle("选择保存物理地址文件的位置");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("CSV Files", "*.csv"));
        fileChooser.setInitialFileName(System.getProjectInfo().makeProjectInfoIntoFileNamePrefix() + "-" + selectedMode.toString() + "-物理地址文件.csv");
        // 使用当前窗口作为父窗口显示文件选择对话框
        File outputFile = fileChooser.showSaveDialog(selectJPGFolder2B.getScene().getWindow());

        if (outputFile == null) {
            result2TA.setText("未选择保存位置");
            DialogUtil.showWarningDialog("警告", "操作有误", "未选择保存位置");
            generatePhysicalAddress2B.setDisable(false);
            return;
        }
        System.setLastModifiedFile(outputFile);
        progressBar.showProgress(SceneManager.getPrimaryStage(), "生成物理路径文件", "正在初始化...");
        // 正确处理文件扩展名 - 只有在没有.csv扩展名时才添加
        final File finalOutputFile;
        if (!outputFile.getName().toLowerCase().endsWith(".csv")) {
            finalOutputFile = new File(outputFile.getAbsolutePath() + ".csv");
        } else {
            finalOutputFile = outputFile;
        }

        // 保存生成的文件路径
        physicalAddressFilePath = finalOutputFile.getAbsolutePath();

        // 创建后台任务
        AddressFileGenerationTask task = new AddressFileGenerationTask(folderPath, outputFile, selectedMode.number, false);
        // 保存到字段
        currentTask = task;
        // 绑定任务属性到UI
        ChangeListener<Number> progressChangeListener = (obs, oldVal, newVal) -> {
            if (newVal != null) {
                if (task.getMessage() != null) {
                    progressBar.updateProgress(newVal.doubleValue(), task.getMessage());
                }
            }
        };
        task.progressProperty().addListener(progressChangeListener);

        // 绑定任务的消息到结果文本区域
        ChangeListener<String> messageChangeListener = (observable, oldValue, newValue) -> {
            result2TA.setText(newValue);
        };
        task.messageProperty().addListener(messageChangeListener);
        // 当任务完成时显示完整结果
        task.setOnSucceeded(e -> {
            progressBar.closeProgress();
            result2TA.setText("生成物理路径 csv 文件任务完成，输出csv文件路径："+task.getValue());
            generatePhysicalAddress2B.setDisable(false);
            log.info(LoggerMarker.RELEASE_MARKER, "生成物理路径 csv 文件任务完成，输出csv文件路径：{}", task.getValue());
            addResultSuccessfulStyle();
        });

        // 处理任务失败情况
        task.setOnFailed(e -> {
            progressBar.closeProgress();
            Throwable exception = task.getException();
            currentTask.progressProperty().removeListener(progressChangeListener);
            currentTask.messageProperty().removeListener(messageChangeListener);
            result2TA.setText("检测过程中发生错误: " + exception.getMessage());
            addResultErrorStyle();
            DialogUtil.showDetailedErrorDialog("错误", "检测过程中发生错误: ", exception.getMessage());
            generatePhysicalAddress2B.setDisable(false);
            log.error(LoggerMarker.RELEASE_MARKER, "生成物理路径 csv 文件任务失败", exception);
        });

        // 处理任务取消情况
        task.setOnCancelled(e -> {
            progressBar.closeProgress();
            currentTask.progressProperty().removeListener(progressChangeListener);
            currentTask.messageProperty().removeListener(messageChangeListener);
            result2TA.appendText("\n检测已取消");
            removeResultStyle();
            generatePhysicalAddress2B.setDisable(false);
            log.info(LoggerMarker.RELEASE_MARKER, "生成物理路径 csv 文件任务已被取消");
        });
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }




    /**
     * On start.
     *
     * @param actionEvent the action event
     */
    @FXML
    void onStart(ActionEvent actionEvent) {
        log.info(LoggerMarker.DEBUG_MARKER, "用户点击了开始对比按钮");

        if (logicalAddressFilePath == null || physicalAddressFilePath == null) {
            result2TA.setText("请先生成逻辑地址文件和物理地址文件。");
            return;
        }
        start2B.setDisable(true);
        removeStartButtonLoadingStyle();
        start2B.setText("比对中...");
        // 显示进度条窗口
        cancelableProgressBar.showProgress(SceneManager.getPrimaryStage(), "文件查漏检查", "正在初始化...");
        // 创建后台任务
        AddressFileComparisonTask task = getAddressFileComparisonTask();
        // 保存到字段
        this.currentTask = task;
        // 绑定任务属性到UI
        ChangeListener<Number> progressChangeListener = (obs, oldVal, newVal) -> {
            if (newVal != null) {
                if (task.getMessage() != null) {
                    cancelableProgressBar.updateProgress(newVal.doubleValue(), task.getMessage());
                }
            }
        };
        task.progressProperty().addListener(progressChangeListener);

        // 绑定任务的消息到结果文本区域
//        ChangeListener<String> messageChangeListener = (observable, oldValue, newValue) -> {
//            result2TA.setText(newValue);
//        };
//        task.messageProperty().addListener(messageChangeListener);

        // 绑定取消按钮 -> task.cancel()
        cancelableProgressBar.setOnCancel(() -> {
            if (currentTask != null && currentTask.isRunning()) {
                currentTask.cancel();
            }
        });

        task.setOnSucceeded(event -> {
            cancelableProgressBar.closeProgress();
            start2B.setDisable(false);
            addStartButtonLoadingStyle();
            start2B.setText("开始对比");
            result2TA.setText(AddressFileComparator.ComparisonResult.generateComparisonResults(task.getValue(), loadFolderType2CB.getValue().compareMode));
            result2TA.setText(AddressFileComparator.ComparisonResult.generateComparisonResults(task.getValue(), loadFolderType2CB.getValue().compareMode));
            //内部比较器已有，此处忽略日志打印
        });

        task.setOnFailed(event -> {
            cancelableProgressBar.closeProgress();
            Throwable exception = task.getException();
            result2TA.setText("文件比对失败: " + exception.getMessage());
            start2B.setDisable(false);
            removeStartButtonLoadingStyle();
            start2B.setText("开始对比");
            DialogUtil.showDetailedErrorDialog("错误", "文件比对失败:", exception.getMessage());
            log.error(LoggerMarker.RELEASE_MARKER, "查漏任务失败", exception);
        });

        task.setOnCancelled(event -> {
            cancelableProgressBar.closeProgress();
            result2TA.appendText("\n检测已取消");
            start2B.setDisable(false);
            removeStartButtonLoadingStyle();
            start2B.setText("开始对比");
            currentTask.progressProperty().removeListener(progressChangeListener);
//            currentTask.messageProperty().removeListener(messageChangeListener);
            log.info(LoggerMarker.RELEASE_MARKER, "查漏任务取消");
        });

        // 异步执行任务
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

    private @NotNull AddressFileComparisonTask getAddressFileComparisonTask() {
        Mode selectedMode = loadFolderType2CB.getValue();
        AddressFileComparator.CompareMode compareMode = (selectedMode == Mode.PAGE_TYPE) ?
                AddressFileComparator.CompareMode.PAGE_LEVEL :
                AddressFileComparator.CompareMode.FILE_LEVEL;

        // 创建异步任务
        return new AddressFileComparisonTask(
                physicalAddressFilePath,
                logicalAddressFilePath,
                compareMode,
                System.getSetting().getTaskTimeout()
        );
    }


    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        loadFolderType2CB.setValue(Mode.PAGE_TYPE);
        loadFolderType2CB.getItems().addAll(Mode.values());
    }

    /**
     * The enum Mode.
     */
    enum Mode {
        /**
         * Jpg mode. 文件以JPG
         */
        PAGE_TYPE("jpg", AddressFileGenerator.PAGE_TYPE,  AddressFileComparator.CompareMode.PAGE_LEVEL) {
            @Override
            public String toString() {
                return "页面级";
            }
        },
        /**
         * Pdf mode. 文件以PDF
         */
        FILE_TYPE("pdf", AddressFileGenerator.FILE_TYPE,  AddressFileComparator.CompareMode.FILE_LEVEL) {
            @Override
            public String toString() {
                return "文件级";
            }
        };
        /**
         * The Id.
         */
        public final String id;
        public final int number;
        public final AddressFileComparator.CompareMode compareMode;

        Mode(String id, int number, AddressFileComparator.CompareMode compareMode) {
            this.id = id;
            this.number = number;
            this.compareMode = compareMode;
        }
    }
    // ======================== 提取的样式变更方法 ========================
    /**
     * 为结果文本域添加错误态样式
     */
    private void addResultErrorStyle() {
        Platform.runLater(() -> {
            result2TA.getStyleClass().add("result-error");
        });
    }
    /**
     * 为结果文本域添加成功态样式
     */
    private void addResultSuccessfulStyle() {
        Platform.runLater(() -> {
            result2TA.getStyleClass().add("result-error");
        });
    }

    /**
     * 为结果文本域移除样式
     */
    private void removeResultStyle() {
        Platform.runLater(() -> {
            result2TA.getStyleClass().remove("result-error");
            result2TA.getStyleClass().remove("result-success");
        });
    }
    /**
     * 为开始按钮添加加载态样式
     */
    private void addStartButtonLoadingStyle() {
        Platform.runLater(() -> {
            start2B.getStyleClass().add("loading");
        });
    }

    /**
     * 为开始按钮移除加载态样式
     */
    private void removeStartButtonLoadingStyle() {
        Platform.runLater(() -> {
            start2B.getStyleClass().remove("loading");
        });
    }
    // ====================================================================
}


