from pathlib import Path
from traceback import format_exc

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog, QApplication, QWidget
from PySide6.QtGui import QGuiApplication
from matplotlib import use
from yaml import dump, load, FullLoader

from func.utils.PublicFunc import PublicFunc
from ui.MainWindow.MainWindow_menu import Ui_Signal_Label

from func.Module_approximately_align import MainWindow_approximately_align
from func.Module_preprocess import MainWindow_preprocess
from func.Module_detect_Jpeak import MainWindow_detect_Jpeak
from func.Module_detect_Rpeak import MainWindow_detect_Rpeak
from func.Module_label_check import MainWindow_label_check
from func.Module_precisely_align import MainWindow_precisely_align
from func.Module_cut_pair_file import MainWindow_cut_PAIR_FILE
from func.Module_artifact_label import MainWindow_artifact_label
from func.Module_bcg_quality_label import MainWindow_bcg_quality_label
from func.Module_resp_quality_label import MainWindow_resp_quality_label
from func.Module_SA_label_v2 import MainWindow_SA_label

from func.utils.ConfigParams import Filename, Params
from func.utils.Constants import Constants


use("QtAgg")
# style.use('dark_background')

# rcParams.update({
#     'figure.facecolor': '#f5f5dc',
#     'axes.facecolor': '#f5f5dc'
# })


Config = {

}

ButtonState = {
    "Default": {
        "pushButton_open": True,
        "pushButton_approximately_align": True,
        "pushButton_preprocess_BCG": True,
        "pushButton_preprocess_ECG": True,
        "pushButton_detect_Jpeak": True,
        "pushButton_detect_Rpeak": True,
        "pushButton_label_check_BCG": True,
        "pushButton_label_check_ECG": True,
        "pushButton_precisely_align": True,
        "pushButton_cut_PSG": True,
        "pushButton_artifact_label": True,
        "pushButton_bcg_quality_label": True,
        "pushButton_resp_quality_label": True,
        "pushButton_SA_label": True
    },
    "Current": {
        "pushButton_open": True,
        "pushButton_approximately_align": True,
        "pushButton_preprocess_BCG": True,
        "pushButton_preprocess_ECG": True,
        "pushButton_detect_Jpeak": True,
        "pushButton_detect_Rpeak": True,
        "pushButton_label_check_BCG": True,
        "pushButton_label_check_ECG": True,
        "pushButton_precisely_align": True,
        "pushButton_cut_PSG": True,
        "pushButton_artifact_label": True,
        "pushButton_bcg_quality_label": True,
        "pushButton_resp_quality_label": True,
        "pushButton_SA_label": True
    }
}


class MainWindow(QMainWindow, Ui_Signal_Label):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_Signal_Label()
        self.ui.setupUi(self)

        # self.setFixedSize(720, 1080)  # 设置固定大小，禁止缩放
        # 获得屏幕分辨率，以3：4比例设置窗口大小，
        screen = QGuiApplication.primaryScreen()
        size = screen.availableGeometry()
        screen_height = size.height()

        window_height = int(screen_height * 0.75)
        window_width = int(window_height * 1 / 2)
        self.resize(window_width, window_height)

        # 消息弹窗初始化
        self.msgBox = QMessageBox()
        self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE)

        self.__read_config__()
        self.ui.plainTextEdit_root_path.setPlainText(Config["Path"]["Root"])
        self.seek_sampID(Path(Config["Path"]["Root"]) / Path(Filename.PATH_ORGBCG_TEXT))

        self.approximately_align = None
        self.preprocess = None
        self.detect_Jpeak = None
        self.detect_Rpeak = None
        self.label_check = None
        self.precisely_align = None
        self.cut_PSG = None
        self.artifact_label = None
        self.bcg_quality_label = None
        self.resp_quality_label = None
        self.SA_label = None

        PublicFunc.__styleAllButton__(self, ButtonState)

        try:
            if QApplication.styleHints().colorScheme() == Qt.ColorScheme.Dark:
                self.ui.checkBox_darkmode.setChecked(True)
            else:
                self.ui.checkBox_darkmode.setChecked(False)
        except Exception as e:
            PublicFunc.msgbox_output(self, Constants.MAINWINDOW_GET_DARKMODE_FAILURE + "。" + format_exc(), Constants.TIPS_TYPE_ERROR)

        # 绑定槽函数
        self.ui.checkBox_darkmode.stateChanged.connect(self.set_dark_mode_status)
        self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__)
        self.ui.pushButton_approximately_align.clicked.connect(self.__slot_btn_approximately_align__)
        self.ui.pushButton_preprocess_BCG.clicked.connect(self.__slot_btn_preprocess__)
        self.ui.pushButton_preprocess_ECG.clicked.connect(self.__slot_btn_preprocess__)
        self.ui.pushButton_detect_Jpeak.clicked.connect(self.__slot_btn_detect_Jpeak__)
        self.ui.pushButton_detect_Rpeak.clicked.connect(self.__slot_btn_detect_Rpeak__)
        self.ui.pushButton_label_check_BCG.clicked.connect(self.__slot_btn_label_check__)
        self.ui.pushButton_label_check_ECG.clicked.connect(self.__slot_btn_label_check__)
        self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__)
        self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__)
        self.ui.pushButton_artifact_label.clicked.connect(self.__slot_btn_artifact_label__)
        self.ui.pushButton_bcg_quality_label.clicked.connect(self.__slot_btn_bcg_quality_label__)
        self.ui.pushButton_resp_quality_label.clicked.connect(self.__slot_btn_resp_quality_label__)
        self.ui.pushButton_SA_label.clicked.connect(self.__slot_btn_SA_label__)

    @staticmethod
    def __read_config__():
        if not Path(Params.PUBLIC_CONFIG_FILE_PATH).exists():
            Path(Params.PUBLIC_CONFIG_FILE_PATH).parent.mkdir(parents=True, exist_ok=True)
            with open(Params.PUBLIC_CONFIG_FILE_PATH, "w") as f:
                dump(Params.PUBLIC_CONFIG_NEW_CONTENT, f)

        with open(Params.PUBLIC_CONFIG_FILE_PATH, "r") as f:
            file_config = load(f.read(), Loader=FullLoader)
            Config.update(file_config)

    @staticmethod
    def __write_config__():
        with open(Path(Params.PUBLIC_CONFIG_FILE_PATH), "w") as f:
            dump(Config, f)

    def __slot_btn_open__(self):
        file_dialog = QFileDialog()
        file_dialog.setFileMode(QFileDialog.Directory)
        file_dialog.setOption(QFileDialog.ShowDirsOnly, True)
        if file_dialog.exec_() == QFileDialog.Accepted:
            self.seek_sampID(Path(file_dialog.selectedFiles()[0]) / Filename.PATH_ORGBCG_TEXT)
            self.ui.plainTextEdit_root_path.setPlainText(file_dialog.selectedFiles()[0])

            # 修改配置
            Config["Path"]["Root"] = str(file_dialog.selectedFiles()[0])
            self.__write_config__()
        else:
            PublicFunc.msgbox_output(self, Constants.OPERATION_CANCELED, Constants.MSGBOX_TYPE_INFO)

    def __slot_btn_approximately_align__(self):
        self.approximately_align = MainWindow_approximately_align()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.approximately_align.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.approximately_align.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_preprocess__(self):
        self.preprocess = MainWindow_preprocess()

        sender = self.sender()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if sender == self.ui.pushButton_preprocess_BCG:
            mode = "BCG"
        elif sender == self.ui.pushButton_preprocess_ECG:
            mode = "ECG"
        else:
            raise ValueError("模式不存在")
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.preprocess.show(mode, root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.preprocess.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_detect_Jpeak__(self):
        self.detect_Jpeak = MainWindow_detect_Jpeak()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.detect_Jpeak.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.detect_Jpeak.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_detect_Rpeak__(self):
        self.detect_Rpeak = MainWindow_detect_Rpeak()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.detect_Rpeak.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.detect_Rpeak.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_label_check__(self):
        self.label_check = MainWindow_label_check()

        sender = self.sender()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()

        if not self.check_root_path():
            return
        if not self.check_sampID():
            return

        if sender == self.ui.pushButton_label_check_BCG:
            mode = "BCG"
        elif sender == self.ui.pushButton_label_check_ECG:
            mode = "ECG"
        else:
            raise ValueError("模式不存在")
        self.label_check.show(mode, root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.label_check.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_precisely_align__(self):
        self.precisely_align = MainWindow_precisely_align()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.precisely_align.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.precisely_align.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_cut_PSG__(self):
        self.cut_PSG = MainWindow_cut_PAIR_FILE()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.cut_PSG.show(root_path, int(sampID))
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_artifact_label__(self):
        self.artifact_label = MainWindow_artifact_label()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.artifact_label.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.artifact_label.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_bcg_quality_label__(self):
        self.bcg_quality_label = MainWindow_bcg_quality_label()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.bcg_quality_label.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.bcg_quality_label.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_resp_quality_label__(self):
        self.resp_quality_label = MainWindow_resp_quality_label()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.resp_quality_label.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.resp_quality_label.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def __slot_btn_SA_label__(self):
        self.SA_label = MainWindow_SA_label()
        root_path = self.ui.plainTextEdit_root_path.toPlainText()
        sampID = self.ui.comboBox_sampID.currentText()
        if not self.check_root_path():
            return
        if not self.check_sampID():
            return
        self.SA_label.show(root_path, int(sampID))
        # 默认最大化显示而非固定分辨率
        self.SA_label.showMaximized()
        self.check_save_path_and_mkdir(root_path, sampID)

    def seek_sampID(self, path):
        if not Path(path).exists():
            PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR)
            self.ui.comboBox_sampID.clear()
            return

        sub_folders = [item.name for item in Path(path).iterdir() if item.is_dir()]
        self.ui.comboBox_sampID.clear()
        self.ui.comboBox_sampID.addItems(sub_folders)
        self.ui.comboBox_sampID.setCurrentIndex(0)

    def check_root_path(self):
        if self.ui.plainTextEdit_root_path.toPlainText() == Constants.STRING_IS_EMPTY:
            PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR)
            return False
        return True

    def check_sampID(self):
        if self.ui.comboBox_sampID.currentText() == Constants.STRING_IS_EMPTY:
            PublicFunc.msgbox_output(self, Constants.MAINWINDOW_SAMPID_EMPTY, Constants.MSGBOX_TYPE_ERROR)
            return False
        return True

    def check_save_path_and_mkdir(self, root_path, sampID):
        path_Label = Path(root_path) / Path(Filename.PATH_LABEL) / Path(str(sampID))
        path_OrgBCG_Aligned = Path(root_path) / Path(Filename.PATH_ORGBCG_ALIGNED) / Path(str(sampID))
        path_PSG_Aligned = Path(root_path) / Path(Filename.PATH_PSG_ALIGNED) / Path(str(sampID))
        path_OrgBCG_Text = Path(root_path) / Path(Filename.PATH_ORGBCG_TEXT) / Path(str(sampID))
        path_PSG_Text = Path(root_path) / Path(Filename.PATH_PSG_TEXT) / Path(str(sampID))

        path_list = [path_Label, path_OrgBCG_Aligned, path_PSG_Aligned, path_OrgBCG_Text, path_PSG_Text]

        for path in path_list:
            if not path.exists():
                path.mkdir(parents=True, exist_ok=True)

    def set_dark_mode_status(self):
        module_list = [
            self,
            self.approximately_align,
            self.preprocess,
            self.detect_Jpeak,
            self.detect_Rpeak,
            self.label_check,
            self.precisely_align,
            self.cut_PSG,
            self.artifact_label,
            self.bcg_quality_label,
            self.resp_quality_label,
            self.SA_label
        ]

        try:
            if self.ui.checkBox_darkmode.isChecked():
                QApplication.styleHints().setColorScheme(Qt.ColorScheme.Dark)
            else:
                QApplication.styleHints().setColorScheme(Qt.ColorScheme.Light)
        except Exception as e:
            PublicFunc.msgbox_output(self, Constants.MAINWINDOW_DARKMODE_FAILURE + "。" + format_exc(), Constants.MSGBOX_TYPE_ERROR)
            return

        for module in module_list:
            try:
                if module is not None:
                    MainWindow.update_widget_style(module)
            except RuntimeError:
                pass

    @staticmethod
    def update_widget_style(mainWindow):
        all_widgets = mainWindow.centralWidget().findChildren(QWidget)
        # 迭代所有部件
        for widget in all_widgets:
            try:
                widget.style().unpolish(widget)
                widget.style().polish(widget)
                widget.update()
            except TypeError:
                pass