"""
/***************************************************************************
 LDMP - A QGIS plugin
 This plugin supports monitoring and reporting of land degradation to the UNCCD
 and in support of the SDG Land Degradation Neutrality (LDN) target.
                              -------------------
        begin                : 2017-05-23
        git sha              : $Format:%H$
        copyright            : (C) 2017 by Conservation International
        email                : trends.earth@conservation.org
 ***************************************************************************/
"""
# pylint: disable=import-error
import typing
from pathlib import Path

import qgis.gui
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import uic
from qgis.core import QgsGeometry
from te_schemas.algorithms import ExecutionScript

from . import conf
from .calculate import DlgCalculateBase
from .jobs.manager import job_manager
from .localexecution import drought
from .logger import log

DlgCalculateDroughtUi, _ = uic.loadUiType(
    str(Path(__file__).parent / "gui/DlgCalculateDrought.ui")
)
DlgCalculateDroughtSummaryUi, _ = uic.loadUiType(
    str(Path(__file__).parent / "gui/DlgCalculateDroughtSummary.ui")
)


class tr_calculate_drought(object):
    def tr(self, message):
        return QtCore.QCoreApplication.translate("tr_calculate_drought", message)


class DlgCalculateDrought(DlgCalculateBase, DlgCalculateDroughtUi):
    def __init__(
        self,
        iface: qgis.gui.QgisInterface,
        script: ExecutionScript,
        parent: QtWidgets.QWidget = None,
    ):
        super().__init__(iface, script, parent)
        self.setupUi(self)

        # TODO: add an option of different population and SPI datasets...
        self.population_dataset_name = "Gridded Population Count (gender breakdown)"
        self.population_dataset = conf.REMOTE_DATASETS["WorldPop"][
            self.population_dataset_name
        ]

        self.spi_dataset_name = "GPCC V6 (Global Precipitation Climatology Centre)"
        self.spi_dataset = conf.REMOTE_DATASETS["SPI"][self.spi_dataset_name]

        # Need a land cover dataset to mask out water areas
        self.lc_dataset_name = "ESA CCI"
        self.lc_dataset = conf.REMOTE_DATASETS["Land cover"][self.lc_dataset_name]

        self.precip_chirps_radio.toggled.connect(self.update_time_bounds)
        self.update_time_bounds()
        self.populate_spi_lags()
        self.lag_cb.setCurrentIndex(self.lag_cb.findText("12"))

        self._finish_initialization()

    def populate_spi_lags(self):
        self.lag_cb.addItems([str(lag) for lag in self.spi_dataset["Lags"]])

    def update_time_bounds(self):
        start_year_pop = self.population_dataset["Start year"]
        end_year_pop = self.population_dataset["End year"]
        start_year_spi = self.spi_dataset["Start year"]
        end_year_spi = self.spi_dataset["End year"]

        start_year = QtCore.QDate(max(start_year_pop, start_year_spi), 1, 1)
        end_year = QtCore.QDate(min(end_year_pop, end_year_spi), 1, 1)

        self.year_initial_de.setMinimumDate(start_year)
        self.year_initial_de.setMaximumDate(end_year)
        self.year_final_de.setMinimumDate(start_year)
        self.year_final_de.setMaximumDate(end_year)

    def btn_calculate(self):
        # Note that the super class has several tests in it - if they fail it
        # returns False, which would mean this function should stop execution
        # as well.
        ret = super(DlgCalculateDrought, self).btn_calculate()

        if not ret:
            return

        crosses_180th, geojsons = self.gee_bounding_box

        year_initial = self.year_initial_de.date().year()
        year_final = self.year_final_de.date().year()

        if (year_final - year_initial) < 5:
            QtWidgets.QMessageBox.warning(
                None,
                self.tr("Error"),
                self.tr(
                    "Initial and final year are less 5 years "
                    "apart in - results will be more reliable "
                    "if more data (years) are included in the analysis."
                ),
            )

            return

        payload = {}
        payload["population"] = {
            "asset": self.population_dataset["GEE Dataset"],
            "source": self.population_dataset_name,
        }

        payload["land_cover"] = {
            "asset": self.lc_dataset["GEE Dataset"],
            "source": self.lc_dataset_name,
        }

        payload["spi"] = {
            "asset": self.spi_dataset["GEE Dataset"],
            "source": self.spi_dataset_name,
            "lag": int(self.lag_cb.currentText()),
        }

        payload.update(
            {
                "geojsons": geojsons,
                "crs": self.aoi.get_crs_dst_wkt(),
                "crosses_180th": crosses_180th,
                "task_name": self.execution_name_le.text(),
                "task_notes": self.task_notes.toPlainText(),
                "script": ExecutionScript.Schema().dump(self.script),
                "year_initial": year_initial,
                "year_final": year_final,
            }
        )

        self.close()

        resp = job_manager.submit_remote_job(payload, self.script.id)

        if resp:
            main_msg = "Submitted"
            description = "Drought indicator task submitted to Trends.Earth server."
        else:
            main_msg = "Error"
            description = (
                "Unable to submit drought indicator task to Trends.Earth server."
            )
        self.mb.pushMessage(
            self.tr(main_msg), self.tr(description), level=0, duration=5
        )

        self.close()


class DlgCalculateDroughtSummary(DlgCalculateBase, DlgCalculateDroughtSummaryUi):
    LOCAL_SCRIPT_NAME: str = "drought-vulnerability-summary"

    button_calculate: QtWidgets.QPushButton
    combo_boxes: typing.Dict[str, drought.SummaryTableDroughtWidgets] = {}

    def __init__(
        self,
        iface: qgis.gui.QgisInterface,
        script: ExecutionScript,
        parent: QtWidgets.QWidget = None,
    ):
        super().__init__(iface, script, parent)
        self.setupUi(self)

        self._finish_initialization()

        self.combo_boxes = drought.SummaryTableDroughtWidgets(
            combo_dataset_drought=self.combo_dataset_drought,
            combo_layer_so3_vulnerability=self.combo_layer_so3_vulnerability,
        )

        self.changed_region.connect(self.combo_boxes.populate)

    def showEvent(self, event):
        super().showEvent(event)
        self.combo_boxes.populate()

    def _validate_dataset_selection(self, combo_box, dataset_name):
        if len(combo_box.dataset_list) == 0:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    f"You must select a {dataset_name} layer "
                    "before you can use the drought tool."
                ),
            )
            return False
        else:
            return True

    def _validate_layer_selection(self, combo_box, layer_name):
        if len(combo_box.layer_list) == 0:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    f"You must select a {layer_name} layer "
                    "before you can use the drought tool."
                ),
            )
            return False
        else:
            return True

    def validate_dataset_selections(self, combo_boxes):
        """validate all needed layers are selected"""
        if not self._validate_dataset_selection(
            combo_boxes.combo_dataset_drought, "drought hazard and exposure"
        ):
            return False
        elif not self._validate_layer_selection(
            combo_boxes.combo_layer_so3_vulnerability, "vulnerability"
        ):
            return False
        else:
            return True

    def validate_layer_extents(self, combo_boxes):
        """Check that the layers cover the full extent of the AOI"""

        if (
            self.aoi.calc_frac_overlap(
                QgsGeometry.fromRect(
                    combo_boxes.combo_dataset_drought.get_current_extent()
                )
            )
            < 0.99
        ):
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "Area of interest is not entirely within the " "drought dataset."
                ),
            )

            return False

        return True

    def btn_calculate(self):
        # Note that the super class has several tests in it - if they fail it
        # returns False, which would mean this function should stop execution
        # as well.
        ret = super().btn_calculate()

        if not ret:
            log(f"failed tests in main class validation (return value {ret})")
            return

        elif not self.validate_dataset_selections(
            self.combo_boxes
        ) or not self.validate_layer_extents(self.combo_boxes):
            log("failed layer validation")

            return
        else:
            log("passed all validation checks")

        params = {
            "task_name": self.options_tab.task_name.text(),
            "task_notes": self.options_tab.task_notes.toPlainText(),
        }
        params.update(
            drought.get_main_drought_summary_job_params(
                task_name=self.options_tab.task_name.text(),
                aoi=self.aoi,
                combo_dataset_drought=self.combo_boxes.combo_dataset_drought,
                combo_layer_so3_vulnerability=self.combo_boxes.combo_layer_so3_vulnerability,
                task_notes=self.options_tab.task_notes.toPlainText(),
            )
        )
        job_manager.submit_local_job_as_qgstask(
            params, script_name=self.LOCAL_SCRIPT_NAME, area_of_interest=self.aoi
        )

        self.close()
