"""
/***************************************************************************
 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
 ***************************************************************************/
"""

import json
from pathlib import Path

from qgis.PyQt import (
    QtWidgets,
    uic
)

import qgis.core
import qgis.gui

from te_schemas.algorithms import AlgorithmRunMode, ExecutionScript

from . import (
    calculate,
    lc_setup,
)
from .jobs.manager import job_manager


DlgCalculateLcUi, _ = uic.loadUiType(
    str(Path(__file__).parent / "gui/DlgCalculateLC.ui"))

from te_schemas.schemas import BandInfo, BandInfoSchema
from te_schemas.land_cover import LCTransitionDefinitionDeg, LCLegendNesting

class DlgCalculateLC(calculate.DlgCalculateBase, DlgCalculateLcUi):
    LOCAL_SCRIPT_NAME = "local-land-cover"

    advanced_configurations: qgis.gui.QgsCollapsibleGroupBox
    scrollAreaWidgetContents: QtWidgets.QWidget

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

        lc_widget_class = {
            AlgorithmRunMode.LOCAL: lc_setup.LandCoverSetupLocalExecutionWidget,
            AlgorithmRunMode.REMOTE: lc_setup.LandCoverSetupRemoteExecutionWidget,
        }[self.script.run_mode]
        self.lc_setup_widget = lc_widget_class(parent=self)
        self.lc_define_deg_widget = lc_setup.LCDefineDegradationWidget()
        self.advanced_configurations.setCollapsed(True)
        self.scrollAreaWidgetContents.layout().insertWidget(0, self.lc_setup_widget)
        self.advanced_configurations.layout().insertWidget(0, self.lc_define_deg_widget)
        self._finish_initialization()

    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(DlgCalculateLC, self).btn_calculate()
        if not ret:
            return

        if self.script.run_mode == AlgorithmRunMode.REMOTE:
            self.calculate_on_GEE()
        elif self.script.run_mode == AlgorithmRunMode.LOCAL:
            self.calculate_locally()
        else:
            raise NotImplementedError

    def calculate_on_GEE(self):
        self.close()
        crosses_180th, geojsons = self.gee_bounding_box

        payload = {
            "year_initial": self.lc_setup_widget.initial_year_de.date().year(),
            "year_final": self.lc_setup_widget.target_year_de.date().year(),
            "geojsons": json.dumps(geojsons),
            "crs": self.aoi.get_crs_dst_wkt(),
            "crosses_180th": crosses_180th,
            'legend_nesting': LCLegendNesting.Schema().dump(
                self.lc_setup_widget.aggregation_dialog.nesting
            ),
            'trans_matrix': LCTransitionDefinitionDeg.Schema().dump(
                self.lc_define_deg_widget.trans_matrix
            ),
            "task_name": self.execution_name_le.text(),
            "task_notes": self.task_notes.toPlainText()
        }
        job = job_manager.submit_remote_job(payload, self.script.id)

        if job is not None:
            main_msg = "Submitted"
            description = "Land cover task submitted to Google Earth Engine."
        else:
            main_msg = "Error"
            description = "Unable to submit land cover task to Google Earth Engine."
        self.mb.pushMessage(
            self.tr(main_msg),
            self.tr(description),
            level=0,
            duration=5
        )

    def calculate_locally(self):

        if len(self.lc_setup_widget.initial_year_layer_cb.layer_list) == 0:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "You must add an initial land cover layer to your map before you "
                    "can run the calculation."
                )
            )
            return

        if len(self.lc_setup_widget.target_year_layer_cb.layer_list) == 0:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "You must add a final land cover layer to your map before you "
                    "can run the calculation."
                )
            )
            return

        year_initial = self.lc_setup_widget.get_initial_year()
        year_final = self.lc_setup_widget.get_final_year()

        if int(year_initial) >= int(year_final):
            QtWidgets.QMessageBox.information(
                None,
                self.tr("Warning"),
                self.tr(
                    'The initial year ({}) is greater than or equal to the target '
                    'year ({}) - this analysis might generate strange '
                    'results.'.format(year_initial, year_final)
                )
            )

        initial_layer = self.lc_setup_widget.initial_year_layer_cb.get_layer()
        initial_extent_geom = qgis.core.QgsGeometry.fromRect(initial_layer.extent())
        if self.aoi.calc_frac_overlap(initial_extent_geom) < .99:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "Area of interest is not entirely within the initial land cover "
                    "layer."
                )
            )
            return

        final_layer = self.lc_setup_widget.target_year_layer_cb.get_layer()
        final_extent_geom = qgis.core.QgsGeometry.fromRect(final_layer.extent())
        if self.aoi.calc_frac_overlap(final_extent_geom) < .99:
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "Area of interest is not entirely within the final land "
                    "cover layer."
                )
            )
            return

        initial_usable = (
            self.lc_setup_widget.initial_year_layer_cb.get_current_band())
        final_usable = self.lc_setup_widget.target_year_layer_cb.get_current_band()
        # TODO: Fix for case where nesting varies between initial and final 
        # bands
        initial_nesting = initial_usable.band_info.metadata.get('nesting')
        final_nesting = final_usable.band_info.metadata.get('nesting')
        if (initial_nesting and final_nesting) and (initial_nesting != final_nesting):
            QtWidgets.QMessageBox.critical(
                None,
                self.tr("Error"),
                self.tr(
                    "Nesting of land cover legends for "
                    "initial and final land cover layer must be identical."
                )
            )
            return

        self.close()

        job_params = {
            "task_name": self.execution_name_le.text(),
            "task_notes": self.task_notes.toPlainText(),
            "year_initial": year_initial,
            "year_final": year_final,
            "lc_initial_path": str(initial_usable.path),
            "lc_initial_band_index": initial_usable.band_index,
            "lc_final_path": str(final_usable.path),
            "lc_final_band_index": final_usable.band_index,
            'legend_nesting': initial_nesting,
            'trans_matrix': LCTransitionDefinitionDeg.Schema().dumps(
                self.lc_define_deg_widget.trans_matrix
            )
        }
        job_manager.submit_local_job(job_params, self.LOCAL_SCRIPT_NAME, self.aoi)
