import os
from typing import Union

import pyqtgraph.parametertree as ptree
from qgis.core import QgsApplication
from qgis.PyQt import QtCore, uic
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QMenu, QWidget

from openlog.__about__ import DIR_PLUGIN_ROOT
from openlog.gui.assay_visualization.config.assay_column_visualization_config import (
    AssayColumnVisualizationConfig,
)
from openlog.gui.assay_visualization.config.assay_visualization_config import (
    AssayVisualizationConfig,
)


class AssayVisualizationConfigWidget(QWidget):
    apply_to_all = QtCore.pyqtSignal()
    apply_to_visible = QtCore.pyqtSignal()
    apply_to_selected = QtCore.pyqtSignal()

    def __init__(
        self,
        parent: QWidget = None,
    ):
        """
        Widget for AssayVisualizationConfig display and edition.
        User can change assay columns configuration.

        Args:
            parent: parent object
        """
        super().__init__(parent)
        self.assay_config = None
        self.setMinimumWidth(300)

        uic.loadUi(
            os.path.join(
                os.path.dirname(__file__), "assay_visualization_config_widget.ui"
            ),
            self,
        )

        self.assay_config = None
        self.assay_column_config = None

        # Add parameter tree
        self.parameter_tree = ptree.ParameterTree(self)
        self.parameter_tree.setHeaderLabels(["Parameter", "Value"])
        self.param_layout.addWidget(self.parameter_tree)

        menu = QMenu(self)

        self.apply_to_all_action = QAction(
            QIcon(str(DIR_PLUGIN_ROOT / "resources" / "images" / "apply_all.svg")),
            "Apply to all",
            self,
        )
        self.apply_to_all_action.triggered.connect(lambda: self.apply_to_all.emit())
        menu.addAction(self.apply_to_all_action)

        self.apply_to_visible_action = QAction(
            QIcon(str(DIR_PLUGIN_ROOT / "resources" / "images" / "apply_visible.svg")),
            "Apply to visible",
            self,
        )
        self.apply_to_visible_action.triggered.connect(
            lambda: self.apply_to_visible.emit()
        )
        menu.addAction(self.apply_to_visible_action)

        self.apply_to_selected_action = QAction(
            QIcon(
                str(DIR_PLUGIN_ROOT / "resources" / "images" / "apply_selection.svg")
            ),
            "Apply to selected",
            self,
        )
        self.apply_to_selected_action.triggered.connect(
            lambda: self.apply_to_selected.emit()
        )
        menu.addAction(self.apply_to_selected_action)

        self.check_all_button.clicked.connect(self.check_all)
        self.uncheck_all_button.clicked.connect(self.uncheck_all)
        self.collapse_button.setIcon(QIcon(QgsApplication.iconPath("mIconExpand.svg")))
        self.collapse_button.setText("")
        self.collapse_button.setToolTip("Collapse all")
        self.collapse_button.clicked.connect(self.collapse)

        self.uncheck_all_button.setText("")
        self.uncheck_all_button.setToolTip("Uncheck all")
        self.uncheck_all_button.setIcon(
            QIcon(
                str(DIR_PLUGIN_ROOT / "resources" / "images" / "icon_uncheck_all.svg")
            )
        )

        self.check_all_button.setText("")
        self.check_all_button.setToolTip("Check all")
        self.check_all_button.setIcon(
            QIcon(str(DIR_PLUGIN_ROOT / "resources" / "images" / "icon_check_all.svg"))
        )

        self.apply_button.setMenu(menu)

    def get_assay_config(
        self,
    ) -> Union[AssayVisualizationConfig, AssayColumnVisualizationConfig, None]:
        """
        Get displayed assay configuration

        Returns: Union[AssayVisualizationConfig,AssayColumnVisualizationConfig,None] display assay configuration

        """
        if self.assay_config:
            return self.assay_config
        if self.assay_column_config:
            return self.assay_column_config
        return None

    def set_assay_config(self, assay_config: AssayVisualizationConfig) -> None:
        """
        Define parameter for an assay configuration

        Args:
            assay_config: (AssayVisualizationConfig)
        """
        self.assay_config = assay_config
        self.assay_column_config = None
        self.toolbar_frame.setVisible(True)

        self.assay_label_values.setText(assay_config.assay_display_name)
        if assay_config.hole_id:
            self.collar_label.setVisible(True)
            self.collar_label_values.setVisible(True)
            self.collar_label_values.setText(assay_config.hole_display_name)
        else:
            self.collar_label.setVisible(False)
            self.collar_label_values.setVisible(False)
            self.collar_label_values.setVisible(False)

        self.parameter_tree.clear()

        # Define params for all assay column
        all_params = ptree.Parameter.create(name="Columns", type="group")
        for param in assay_config.get_pyqtgraph_params():
            all_params.addChild(param)
        for col, assay_column_config in assay_config.column_config.items():
            all_params.addChild(assay_column_config.get_pyqtgraph_param())

        self.parameter_tree.setParameters(all_params, showTop=False)

        for assay_column_config in assay_config.column_config.values():
            for w in assay_column_config.create_configuration_widgets(self):
                self.param_layout.addWidget(w)

    def set_assay_column_config(
        self, assay_column_config: AssayColumnVisualizationConfig
    ) -> None:
        """
        Define parameter for an assay configuration

        Args:
            assay_config: (AssayVisualizationConfig)
        """
        self.assay_column_config = assay_column_config
        self.assay_config = None
        self.toolbar_frame.setVisible(False)

        self.assay_label_values.setText(assay_column_config.column.display_name)
        if assay_column_config.hole_id:
            self.collar_label_values.setText(assay_column_config.hole_display_name)
        else:
            self.collar_label.setVisible(False)
            self.collar_label_values.setVisible(False)

        self.parameter_tree.clear()

        # Define params for all assay column
        all_params = ptree.Parameter.create(name="Columns", type="group")
        all_params.addChild(assay_column_config.get_pyqtgraph_param())

        self.parameter_tree.setParameters(all_params, showTop=False)

        for w in assay_column_config.create_configuration_widgets(self):
            self.param_layout.addWidget(w)

    def check_all(self) -> None:
        """
        Check all visibility parameters for displayed configuration

        """
        self._check_all(True)

    def uncheck_all(self) -> None:
        """
        Uncheck all visibility parameters for displayed configuration

        """
        self._check_all(False)

    def _check_all(self, checked: bool) -> None:
        """
        Check or uncheck all visibility parameters for displayed configuration

        Args:
            checked: (bool) visibility parameter value
        """
        if not self.assay_config:
            return
        for col, assay_column_config in self.assay_config.column_config.items():
            assay_column_config.visibility_param.setValue(checked)

    def collapse(self, only_if_multiple: bool = False) -> None:
        """
        Collapse all visibility parameters.
        Args:
            - only_if_multiple: bool If True, collapse only if multiple configs

        """
        if not self.assay_config:
            return

        if only_if_multiple and len(self.assay_config.column_config) < 2:
            return
        for col, assay_column_config in self.assay_config.column_config.items():
            assay_column_config.visibility_param.setOpts(syncExpanded=True)
            assay_column_config.visibility_param.setOpts(expanded=False)
