from typing import Callable, Dict, List

from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton

from grm.lib.Util import MsError, MsInfo
from grm.ui.Weather_data import Ui_Dialog


class ClimateDataDialog(QDialog):
    def __init__(self, xmltodict={"GRMProject": {"ProjectSettings": {}}}, parent=None):
        super(ClimateDataDialog, self).__init__(parent)
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        # 얕은 복사. 해당 값은 주의깊게 사용해야 한다.
        self.__xmltodict = xmltodict

        self.attr_value_dict = {}
        self.__require_attr_list = [
            "PrecipitationDataFile",
            "PrecipitationInterval_min",
        ]
        self.__set_xml_to_attr()
        self.__set_initial_value()
        self.__set_btn_browse_event()
        self.__set_spb_event()

        self.ui.btnCancel.clicked.connect(self.close)
        self.ui.btnOK.clicked.connect(self.__btn_ok_clicked)

    def __error_handler_decorator(func: Callable) -> Callable:
        def wrapper(self, *args, **kwargs):
            try:
                func(self, *args, **kwargs)
            except Exception as e:
                return MsError(e, self)

        return wrapper

    def __set_xml_to_attr(self):
        """
        xml에 있는 값들을 클래스 내의 attr_value_dict에 저장한다.
        """

        attr_list = [
            "PrecipitationDataFile",
            "PrecipitationInterval_min",
            "TemperatureMaxDataFile",
            "TemperatureMaxInterval_min",
            "TemperatureMinDataFile",
            "TemperatureMinInterval_min",
            "DaytimeLengthDataFile",
            "DaytimeLengthInterval_min",
            "DaytimeHoursRatioDataFile",
            "SolarRadiationDataFile",
            "SolarRadiationInterval_min",
            "SnowPackTemperatureDataFile",
            "SnowPackTemperatureInterval_min",
        ]

        for attr in attr_list:
            if self.__xmltodict["GRMProject"]["ProjectSettings"].get(attr):
                self.attr_value_dict[attr] = self.__xmltodict["GRMProject"][
                    "ProjectSettings"
                ][attr]
            else:
                self.attr_value_dict[attr] = None

    def __set_initial_value(self):
        for attr in self.attr_value_dict.keys():
            attr_value = self.attr_value_dict.get(attr)
            if attr_value:
                if attr.endswith("_min"):
                    getattr(self.ui, f"spb_{attr}").setValue(int(attr_value))
                elif attr.endswith("File"):
                    getattr(self.ui, f"path_{attr}").setText(attr_value)

    def __set_btn_browse_event(self) -> None:
        load_list: List[str] = [
            string.split("load_btn_")[1]
            for string in dir(self.ui)
            if string.startswith("load_btn_")
        ]
        btn_line_edit_dict: Dict[QPushButton, QLineEdit] = {
            getattr(self.ui, f"load_btn_{load}"): getattr(self.ui, f"path_{load}")
            for load in load_list
        }

        for btn, line_edit in btn_line_edit_dict.items():
            btn.clicked.connect(self.__btn_click_browse(line_edit))

    def __btn_click_browse(self, line_edit: QLineEdit) -> Callable:
        def browse():
            file_path = QFileDialog.getOpenFileName(self, "Select file")[0]
            line_edit.setText(file_path)
            self.attr_value_dict[line_edit.objectName().split("path_")[1]] = file_path

        return browse

    def __set_spb_event(self) -> None:
        spb_list: List[str] = [
            string.split("spb_")[1]
            for string in dir(self.ui)
            if string.startswith("spb_")
        ]
        for spb in spb_list:
            getattr(self.ui, f"spb_{spb}").valueChanged.connect(
                self.__spb_value_changed(spb)
            )

    def __spb_value_changed(self, attr: str) -> Callable:
        def value_changed():
            self.attr_value_dict[attr] = getattr(self.ui, f"spb_{attr}").value()

        return value_changed

    @__error_handler_decorator
    def __btn_ok_clicked(self, _: bool) -> None:
        for attr in self.__require_attr_list:
            if not self.attr_value_dict.get(attr):
                raise Exception(f"해당 속성 값이 필요합니다. : '{attr}'")

        for attr in self.attr_value_dict.keys():
            if (
                self.attr_value_dict.get(attr)
                and attr in self.__xmltodict["GRMProject"]["ProjectSettings"].keys()
            ):
                self.__xmltodict["GRMProject"]["ProjectSettings"][
                    attr
                ] = self.attr_value_dict.get(attr)

        MsInfo("Weather Data setup is completed. ")
        self.close()


if __name__ == "__main__":
    import os

    from grm.lib.Util import MsTitle

    os.environ[
        "QT_QPA_PLATFORM_PLUGIN_PATH"
    ] = r"C:\Program Files\QGIS 3.10\apps\Qt5\plugins"
    import sys

    from qgis.PyQt.QtWidgets import QApplication

    MsTitle("ClimateDataDialog")
    app = QApplication(sys.argv)
    ui = ClimateDataDialog(
        {
            "GRMProject": {
                "ProjectSettings": {
                    "PrecipitationDataFile": "",
                    "PrecipitationInterval_min": "",
                    "TemperatureMaxDataFile": "",
                    "TemperatureMaxInterval_min": "",
                    "TemperatureMinDataFile": "",
                    "TemperatureMinInterval_min": "",
                    "DaytimeLengthDataFile": "",
                    "DaytimeLengthInterval_min": "",
                    "DaytimeHoursRatioDataFile": "",
                    "SolarRadiationDataFile": "",
                    "SolarRadiationInterval_min": "",
                    "SnowPackTemperatureDataFile": "",
                    "SnowPackTemperatureInterval_min": "",
                }
            }
        }
    )
    ui.show()
    sys.exit(app.exec_())
