"""
/***************************************************************************
 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 Google Earth Engine."
        else:
            main_msg = "Error"
            description = "Unable to submit drought indicator task to Google Earth Engine."
        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_jrc_vulnerability=self.combo_layer_jrc_vulnerability
        )

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

    def validate_layer_selections(self, combo_boxes):
        '''validate all needed layers are selected'''

        if combo_boxes.combo_dataset_drought.currentText == '':
            QtWidgets.QMessageBox.critical(
                None, self.tr("Error"),
                self.tr(
                    "You must choose an drought dataset before using "
                    "the drought vulnerability calculation tool."
                )
            )

            return False

        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()
            )
        ) < .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 validate_layer_crs(self, combo_boxes):
        '''check all productivity layers have the same resolution and CRS'''
        def res(layer):
            return (
                round(layer.rasterUnitsPerPixelX(),
                      10), round(layer.rasterUnitsPerPixelY(), 10)
            )

        if res(combo_boxes.combo_layer_pop.get_layer()
               ) != res(combo_boxes.combo_layer_spi.get_layer()):
            QtWidgets.QMessageBox.critical(
                None, self.tr("Error"),
                self.
                tr("Resolutions of population and SPI datasets do not match.")
            )

            return False

        if combo_boxes.combo_layer_pop.get_layer().crs(
        ) != combo_boxes.combo_layer_spi.get_layer().crs():
            QtWidgets.QMessageBox.critical(
                None, self.tr("Error"),
                self.tr(
                    "Coordinate systems of population and SPI datasets do not match."
                )
            )

            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:
            return

        if (
            not self.validate_layer_selections(self.combo_boxes) or
            # not self.validate_layer_crs(self.combo_boxes) or
            not self.validate_layer_extents(self.combo_boxes)
        ):
            log('failed layer validation')

            return

        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_jrc_vulnerability=self.combo_boxes.
                combo_layer_jrc_vulnerability,
                task_notes=self.options_tab.task_notes.toPlainText()
            )
        )
        job_manager.submit_local_job(
            params,
            script_name=self.LOCAL_SCRIPT_NAME,
            area_of_interest=self.aoi
        )

        self.close()
