# -*- coding: utf-8 -*-


from pathlib import Path

from qgis.PyQt.QtWidgets import (
    QWidget,
    QPushButton,
    QMessageBox,
)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QSortFilterProxyModel

# from ..constants import SITUATION_CHART_BASE_CSV_PATH
from ...constants import SITUATION_CHART_BASE_CSV_PATH
from ...charts import (
    ChartToolBarWithColormap,
    EvolutionChart,
    SituationChart,
    HighlightPoint,
    ChartToolBar,
)
from ...helpers import analyse_results_directory
from ...result_layers_importer import (
    SelectableFolder,
    get_selectable_folders,
    import_selected_result_layers,
)
from ....dataclasses import ScenarioResult
from ...results_table_model import ResultsTableModel

from ..situation_selector_widget.situation_selector_widget import (
    ScenariosSituationSelectorWidget,
)
from ...widgets.situation_selector_widget.situation_entities import (
    SituationSelection,
)
from ..result_layers_selector_widget.result_layers_selector_dialog import (
    ResultLayersSelectorDialog,
)

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(
    Path(__file__).parent / "scenarios_result_viewer_widget.ui"
)


class ScenariosResultViewerWidget(QWidget, FORM_CLASS):

    def __init__(self, parent=None):
        """constructor"""
        super(ScenariosResultViewerWidget, self).__init__(parent)
        self._parent = parent

        # self.scenarios_history: list[ScenarioResult] = []
        self._situation_chart: SituationChart = SituationChart(self)
        self._situation_selector: ScenariosSituationSelectorWidget = (
            ScenariosSituationSelectorWidget(self)
        )
        self._evolution_chart: EvolutionChart = EvolutionChart(self)
        self._results_table_model = ResultsTableModel()
        self._results: list[ScenarioResult] = []
        self._result_directory_path: Path = Path()
        self._push_button_load_layers: QPushButton | None = None
        self._result_layers_selector_dialog: ResultLayersSelectorDialog = (
            ResultLayersSelectorDialog(self)
        )
        # Setup Ui
        self.setupUi(self)
        self.setup_gui()

    def setup_gui(self) -> None:
        """setup gui widget properties"""
        self.setup_exploitation_situation_chart()
        self.setup_evolution_grain_chart()
        self.setup_results_table()
        self.setup_load_layers_button()
        self.comboBox_id_exploitation.currentIndexChanged.connect(
            self.refresh_exploitation_results_tab
        )
        self.set_selected_exploitation_label(None)
        self._situation_selector.selection_changed.connect(
            self.filter_situation_chart_by_situation_selection
        )

    def setup_load_layers_button(self) -> None:
        """Add the load-layers button ."""

        self._push_button_load_layers = QPushButton("Charger les couches", self)
        self._push_button_load_layers.clicked.connect(self.on_load_layers_clicked)
        self.horizontalLayout.insertWidget(2, self._push_button_load_layers)

    def on_load_layers_clicked(self) -> None:
        """Load result rasters for the currently selected exploitation."""
        if self.comboBox_id_exploitation.currentIndex() == -1:
            QMessageBox.warning(
                self,
                "Erreur",
                "Veuillez sélectionner une exploitation.",
            )
            return

        id_exploitation: str = self.comboBox_id_exploitation.currentText()
        exploitation_folder: Path | None = self._resolve_exploitation_folder(
            id_exploitation
        )
        if exploitation_folder is None:
            QMessageBox.warning(
                self,
                "Erreur",
                f"Dossier de résultats introuvable pour l'exploitation {id_exploitation}.",
            )
            return

        selectable_folders: list[SelectableFolder] = get_selectable_folders(
            exploitation_folder
        )
        if not selectable_folders:
            QMessageBox.warning(
                self,
                "Erreur",
                "Aucun dossier de résultats disponible à charger.",
            )
            return

        selections = self._result_layers_selector_dialog.run(
            id_exploitation=id_exploitation,
            folders=selectable_folders,
        )
        if not selections:
            return

        import_selected_result_layers(
            id_exploitation=id_exploitation,
            selections=selections,
        )

    def _resolve_exploitation_folder(self, id_exploitation: str) -> Path | None:
        """Resolve the exploitation folder from the configured result directory."""
        if not self._result_directory_path.exists():
            return None

        exploitation_folder = self._result_directory_path / id_exploitation
        if exploitation_folder.is_dir():
            return exploitation_folder
        return None

    def setup_exploitation_situation_chart(self) -> None:
        """setup exploitation situation chart"""
        self.verticalLayout_results_situation.addWidget(
            self._situation_selector, alignment=Qt.AlignLeft
        )

        self._situation_chart.load_csv(str(SITUATION_CHART_BASE_CSV_PATH))
        situation_tool_bar: ChartToolBarWithColormap = ChartToolBarWithColormap(
            self._situation_chart, self
        )
        situation_tool_bar.setMaximumSize(16777215, 60)
        self.verticalLayout_results_situation.addWidget(
            self._situation_chart.get_canvas()
        )
        self.verticalLayout_results_situation.addWidget(situation_tool_bar)

    def filter_situation_chart_by_situation_selection(
        self, situation_selection: SituationSelection
    ) -> None:
        """filter situation chart by situation selection"""
        self._situation_chart.filter_by_situation_selection(situation_selection)

    def setup_evolution_grain_chart(self) -> None:
        """setup exploitation situation result graph"""
        # adding canvas to the layout

        evolution_tool_bar: ChartToolBar = ChartToolBar(self._evolution_chart, self)
        evolution_tool_bar.setMaximumSize(16777215, 60)
        # adding canvas to the layout
        self.verticalLayout_results_evolution_grain.addWidget(
            self._evolution_chart.get_canvas()
        )
        self.verticalLayout_results_evolution_grain.addWidget(evolution_tool_bar)

    def setup_results_table(self) -> None:
        """setup results table"""
        sortable_proxy_model = QSortFilterProxyModel()
        sortable_proxy_model.setSourceModel(self._results_table_model)
        self.tableView_results.setSortingEnabled(True)
        self.tableView_results.setModel(sortable_proxy_model)

    def set_result_directory_path(self, result_directory_path: Path) -> None:
        """Set the result directory path"""
        self._result_directory_path = result_directory_path
        self.update_results()

    def update_results(self) -> None:
        """Refresh results"""
        # set results by analysing the files in the result directory so the results can be used to populate the id_exploitation_combobox
        self.set_results()
        #  get list of id exploitation
        self.populate_id_exploitation_combobox()

    def set_selected_exploitation_id(self, id_exploitation: str) -> None:
        """Set the selected exploitation id"""
        if id_exploitation not in set(
            [result.id_exploitation for result in self._results]
        ):
            self.comboBox_id_exploitation.setCurrentIndex(-1)
            return
        self.comboBox_id_exploitation.setCurrentText(id_exploitation)

    def refresh_exploitation_results_tab(self):
        """Update results tab with the results of the last process"""
        # reset results to refresh results if any scenario has been added meanwhile
        if self.comboBox_id_exploitation.currentIndex() == -1:
            # clear the charts and table
            self._situation_chart.clear_highlight_points()
            self._evolution_chart.clear_highlight_points()
            self._results_table_model.clear_data()
            return
        id_exploitation: str = self.comboBox_id_exploitation.currentText()
        self.set_selected_exploitation_label(id_exploitation)
        self.update_evolution_chart_from_results(id_exploitation)
        self.update_situation_chart_from_results(id_exploitation)
        self.update_results_table(id_exploitation)

    def set_results(self) -> None:
        if self._result_directory_path.exists():
            self._results = analyse_results_directory(
                results_directory=self._result_directory_path,
            )
        else:
            self._results = []

    def update_evolution_chart_from_results(self, id_exploitation: str):
        """Update graph from results"""
        highlight_points_evolution: list[HighlightPoint] = []
        for result in self._results:
            if result.id_exploitation == id_exploitation:
                highlight_points_evolution.append(
                    HighlightPoint(
                        result.delta_gb,
                        result.delta_seuil_gb,
                        result.scenario_name,
                    )
                )
        self._evolution_chart.set_highlight_points(highlight_points_evolution)
        self._evolution_chart.draw_chart()

    def update_situation_chart_from_results(self, id_exploitation: str):
        """Update graph from results"""
        highlight_points_situation: list[HighlightPoint] = []
        for result in self._results:
            if (
                result.id_exploitation == id_exploitation
                and result.scenario_name == "initial"
            ):
                highlight_points_situation.append(
                    HighlightPoint(
                        result.tx_boisement_externe,
                        result.tx_boisement_interne,
                        result.scenario_name,
                    )
                )
        self._situation_chart.set_highlight_points(highlight_points_situation)
        self._situation_chart.draw_chart()

    def update_results_table(self, id_exploitation: str):
        """Update results table"""
        results: list[ScenarioResult] = [
            result
            for result in self._results
            if result.id_exploitation == id_exploitation
        ]
        self._results_table_model.set_data(results)

    def set_selected_exploitation_label(self, id_exploitation: str | None) -> None:
        """Set the selected exploitation label"""
        if id_exploitation is None:
            self.label_results_exploitation_id.setText(
                "Aucune exploitation sélectionnée"
            )
            return
        self.label_results_exploitation_id.setText(
            f"Résultats pour l'exploitation {id_exploitation}"
        )

    def populate_id_exploitation_combobox(self) -> None:
        """populate id exploitation combobox"""
        self.set_selected_exploitation_label(None)
        self.comboBox_id_exploitation.clear()
        # get a set of id_exploitation
        id_exploitation_set: set[str] = set(
            result.id_exploitation for result in self._results
        )

        self.comboBox_id_exploitation.addItems(sorted(id_exploitation_set))
