# -*- coding: utf-8 -*-
"""
/***************************************************************************
 PluginGeometryDialog
 This plugin connects to the NDFF api
                             -------------------
        begin                : 2021-12-20
        git sha              : $Format:%H$
        copyright            : (C) 2021 by Zuidt
        email                : richard@zuidt.nl
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import os

from qgis.PyQt import uic

from qgis.PyQt.QtWidgets import (
    QDialog,
    QRadioButton,
    QMessageBox,
)

from qgis.core import (
    QgsVectorLayer,
)

from .ext.ndff.connector import NdffConnector

import logging
from . import LOGGER_NAME
log = logging.getLogger(LOGGER_NAME)

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'ndffc_plugin_geometry_dialog_base.ui'))


class PluginGeometryDialog(QDialog, FORM_CLASS):

    # Title to be used for all plugin dialogs (if possible)
    PLUGIN_DIALOGS_TITLE = 'NDFF Connector Plugin'

    def __init__(self, parent=None):
        """
        When the user chooses to see/change the location(s) field(s), it pops up this dialog

        See show_dialog for more information.

        The active radio-button upon 'accept' actually SETS the choice (and unsets the others)

        """
        super(PluginGeometryDialog, self).__init__(parent)

        self.setupUi(self)
        self.radio_qgis_geom.toggled.connect(lambda: self.location_page_changed(self.radio_qgis_geom))
        self.radio_x_y_geom.toggled.connect(lambda: self.location_page_changed(self.radio_x_y_geom))
        self.radio_ewkt_geom.toggled.connect(lambda: self.location_page_changed(self.radio_ewkt_geom))

        self.combo_location.fieldChanged.connect(self.location_field_set)
        self.combo_location_x.fieldChanged.connect(self.location_x_set)
        self.combo_location_y.fieldChanged.connect(self.location_y_set)

        self.record = None
        self.connector = None

        # IF the layer is a QGIS layer, we can get the Location/Geometry from the layer by default
        # IF it is NOT a QGIS layer, we disable the 'radio_qgis_geom'
        # if self.data_record.hasGeometry():
        #     self.main_dlg.radio_qgis_geom.setEnabled(True)
        # else:
        #     self.main_dlg.radio_qgis_geom.setEnabled(False)
        #     self.main_dlg.radio_x_y_geom.setChecked(True)
        # not sure if this is working yet...
        # if 'location' in self.data_record.attributes() and self.data_record['location'] is not None:
        #     self.main_dlg.radio_ewkt_geom.setChecked(True)
        # if ('location_x' in self.data_record.attributes() and self.data_record['location_x'] is not None) \
        #         or ('location_y' in self.data_record.attributes() and self.data_record['location_y'] is not None):
        #     self.main_dlg.radio_x_y_geom.setChecked(True)

        # if self.main_dlg.radio_qgis_geom.isChecked():
        #     # OK, user wants us to use the QGIS geometry:
        #     if isinstance(self.data_record, QgsFeature) and self.data_record.hasGeometry():  # extra check
        #         geom = self.data_record.geometry()
        #         point = None
        #         if geom.type() == QgsWkbTypes.PointGeometry and QgsWkbTypes.isSingleType(geom.wkbType()):
        #             # Eg: Point (184876.311529 567272.6489911)
        #             point = geom.asPoint()  # we want QgsPoint
        #             observation.set('location', geom.asWkt())
        #         elif geom.type() == QgsWkbTypes.PointGeometry and QgsWkbTypes.isMultiType(geom.wkbType()):
        #             # MultiPoint ((184876.31152926472714171 567272.64899118163157254))
        #             for part in geom.parts():
        #                 if point is None:
        #                     point = part  # parts of a MultiPoint are already QgsPoint
        #                     observation.set('location', point.asWkt())
        #                 else:
        #                     # check if there are more points?
        #                     raise Exception('Layer with MultiPoint geometry type, containing > 1 point per geom... not sure how to handle this...')
        #         elif geom.type() == QgsWkbTypes.PolygonGeometry and QgsWkbTypes.isSingleType(geom.wkbType()):
        #             # Eg Polygon: POLYGON ((4.41042 51.86444, 4.41042 51.86444, 4.410441 51.86443, 4.41044 51.86444, 4.41042 51.86444))
        #             observation.set('location', geom.asWkt())
        #         else:
        #             # TODO handle linestrings and polygons both single and multi types
        #             log.debug(f'User wants us to use the QGIS QgsGeometry for layer "{self.current_layer.name()}", but this type {geom} is not yet implemented...')
        #             QMessageBox.information(self.iface.mainWindow(), self.PLUGIN_DIALOGS_TITLE, f'User wants us to use the QGIS QgsGeometry for layer "{self.current_layer.name()}", but this type {geom} is not yet implemented...')
        #
        #         # special QGIS geometry field set, put the geoms in that button/label
        #         if point and observation.geom:
        #             coord_format = ".2f"  # defaulting to coordinates with 2 decimals (EPSG:28992)
        #             if float(point.x()) < 180:  # probably EPSG:4326: lat lon coordinates
        #                 coord_format = ".8f"
        #             self.main_dlg.example_location_qgis.setText(", ".join(format(x, coord_format) for x in observation.geom['geometry']['coordinates']))
        #         elif observation.geom:
        #             self.main_dlg.example_location_qgis.setText(f"{observation.get('location')[0:75]} ...")
        #         else:
        #             self.main_dlg.example_location_qgis.setText('???')
        #     else:
        #         log.debug('User want us to use the QGIS QgsGeometry, but something went wrong...')
        #         QMessageBox.information(self.iface.mainWindow(), self.PLUGIN_DIALOGS_TITLE, 'User want us to use the QGIS QgsGeometry, but something went wrong...')

    def show_dialog(self, connector: NdffConnector, record: dict, layer: QgsVectorLayer):
        """
        There are 3 options:
        - the user chooses a wkt column, and set the 'location' mapping to that field (and unset location_x and location_y)
        - the user chooses 2 x,y columns and set 'location_x' and 'location_y' to those fields (and unset location)
        - the user chooses to use the QGIS column (IF available) then the location^* fields SHOULD ALL BE UNSET!!
        Within a QGIS layer all three can potentially be available.

        So when the dialog shows up, we:
        - check the field_mappings: order is preference
            - location_x and location_y set -> make those checked and show it
            - location set? -> make location radio checked and show it
            - nothing set and QGIS/geom layer -> make qgis checked and show it
            - nothing set and table layer -> disable qgis, default to xy and show nothing
        When in the dialog the user should be able to set/see all options, but:

        The active radio-button upon 'accept' actually SETS the choice (and unsets the others)

        """
        self.connector = connector
        self.record = record

        self.combo_location_x.setLayer(layer)
        self.combo_location_y.setLayer(layer)
        self.combo_location.setLayer(layer)

        # cleanup of combos
        self.combo_location_x.setField('')
        self.combo_location_y.setField('')
        self.combo_location.setField('')
        # cleanup of values
        self.example_location_x.setText('')
        self.example_location_y.setText('')
        self.example_location.setText('')
        self.example_location_qgis.setText('')

        # we added a field 'geometry' to the record IF the original feature (in QGIS)
        #   actually HAS a geometry (that is: was not a table-only layer)
        if 'geometry' in record and record['geometry']:
            self.radio_qgis_geom.setEnabled(True)
        else:
            # we are re-using the dialog, so be sure to unset it too
            self.radio_qgis_geom.setEnabled(False)

        # check if here are actually mappings, and if so
        # make that checked and show it:
        if connector.get_field_mapping('location_x') or connector.get_field_mapping('location_y'):
            log.debug("GEOM: we have a 'location_x' AND 'location_y' mapped...")
            self.radio_x_y_geom.setChecked(True)
            self.combo_location_x.setField(self.connector.get_field_mapping('location_x'))
            self.combo_location_y.setField(self.connector.get_field_mapping('location_y'))
        elif connector.get_field_mapping('location') or 'location' in record:
            log.debug("GEOM: we have a mapping for 'location...")
            self.radio_ewkt_geom.setChecked(True)
            self.combo_location.setField(self.connector.get_field_mapping('location'))
        elif 'geometry' in record and record['geometry']:
            # try to use the QGIS geom from this record
            # Toggle to force the showing of the geom
            self.radio_ewkt_geom.setChecked(True)
            self.location_page_changed(self.radio_x_y_geom)
            self.radio_qgis_geom.setChecked(True)
        else:  # no location fields set in mappings, AND NO geometry in data
            self.radio_x_y_geom.setChecked(True)
        self.show()

    def accept(self) -> None:
        # NOW we have to actually SET the location field mapping IF set, based on current active radio
        if self.radio_qgis_geom.isChecked():
            # remove the potentially available location, location_x and location_y field mappings
            self.connector.set_field_mapping('location', '')
            self.connector.set_field_mapping('location_x', '')
            self.connector.set_field_mapping('location_y', '')
            # nothing to set here... the plugin will try to use the QgisGeometry IF all location fields are Unset
        elif self.radio_x_y_geom.isChecked():
            # remove the potentially available location field mapping
            self.connector.set_field_mapping('location', '')
            # set the location_x and location_y mapping
            # BUT they should both have a (valid?) value
            if self.combo_location_x.currentField() in ('', None) or self.combo_location_y.currentField() in ('', None):
                QMessageBox.information(self, self.PLUGIN_DIALOGS_TITLE, 'BEIDE velden moeten worden gezet: x EN y ...')
                return
            try:
                float(self.record[self.combo_location_x.currentField()])
            except ValueError:
                QMessageBox.information(self, self.PLUGIN_DIALOGS_TITLE, f'De waarde voor het x veld: "{self.combo_location_x.currentField()}", lijkt geen geldig getal: "{self.record[self.combo_location_x.currentField()]}"')
                return
            try:
                float(self.record[self.combo_location_y.currentField()])
            except ValueError:
                QMessageBox.information(self, self.PLUGIN_DIALOGS_TITLE, f'De waarde voor het y veld: "{self.combo_location_y.currentField()}", lijkt geen geldig getal: "{self.record[self.combo_location_y.currentField()]}"')
                return
            self.connector.set_field_mapping('location_x', self.combo_location_x.currentField())
            self.connector.set_field_mapping('location_y', self.combo_location_y.currentField())
        elif self.radio_ewkt_geom.isChecked():
            # remove the potentially available location_x and location_y field mappings
            self.connector.set_field_mapping('location_x', '')
            self.connector.set_field_mapping('location_y', '')
            # set the location mapping
            # BUT should valid WKT or EWKT
            if len(self.combo_location.currentField().strip()) > 0 and self.connector.is_valid_wkt(str(self.record[self.combo_location.currentField()])):
                self.connector.set_field_mapping('location', self.combo_location.currentField())
            else:
                # other than single point (e)wkt not yet implemented?
                QMessageBox.information(self, self.PLUGIN_DIALOGS_TITLE, f'De waarde voor het wkt veld: "{self.combo_location.currentField()}", lijkt geen geldig WKT point\nAndere waarden worden (nog) niet geaccepteerd...')
                return
        self.done(QDialog.Accepted)

    def location_page_changed(self, radio_geom: QRadioButton):
        """
        Change the 'location'-page, the page in which to set the (type) of
        location: from a QgsGeometry, from an X and Y, from an (E)WKT-string
        """
        if radio_geom.objectName() == 'radio_qgis_geom' and radio_geom.isChecked():
            self.stack_location.setCurrentIndex(0)
            self.example_location_qgis.setText(self.record['geometry'].asWkt())
        elif radio_geom.objectName() == 'radio_x_y_geom' and radio_geom.isChecked():
            self.stack_location.setCurrentIndex(1)
        elif radio_geom.objectName() == 'radio_ewkt_geom' and radio_geom.isChecked():
            self.stack_location.setCurrentIndex(2)

    def location_field_set(self):
        log.debug(f'location_field_SET to {self.combo_location.currentField()}')
        self.show_field_value('location', self.combo_location.currentField(), self.example_location)

    def location_x_set(self):
        log.debug(f'location_x_field_SET to {self.combo_location_x.currentField()}')
        self.show_field_value('location_x', self.combo_location_x.currentField(), self.example_location_x)

    def location_y_set(self):
        log.debug(f'location_y_field_SET to {self.combo_location_y.currentField()}')
        self.show_field_value('location_y', self.combo_location_y.currentField(), self.example_location_y)

    def show_field_value(self, field, mapped_to, button_to_show_on):
        if self.record and mapped_to in self.record:
            # we have mappings, data and the data contains the mapping
            button_to_show_on.setText(f'[ {self.record[mapped_to]} ]')
        elif self.record and self.connector.get_field_default(field):
            button_to_show_on.setText(f'{self.connector.get_field_default(field)}')
        else:
            button_to_show_on.setText('-')
