# -*- coding: utf-8 -*-
"""
/***************************************************************************
 PluginMapDefaultDialog
 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,
    QMessageBox,
)
from qgis.PyQt.QtCore import QUrl, Qt
from qgis.PyQt.QtGui import QDesktopServices
from qgis.core import (
    QgsWkbTypes,
)
from .ext.ndff.connector import (
    NdffConnector,
)
from .ext.ndff.exceptions import (
    NdffException,
)
import logging
from . import LOGGER_NAME
from .ndffc_plugin_search_code_dialog import PluginSearchCodeDialog

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_map_or_default_dialog_base.ui'))


class PluginMapDefaultDialog(QDialog, FORM_CLASS):
    """
    This Dialog is a dialog to map a data field/column to an observation field/column

    """

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

    def __init__(self, parent=None):
        """Constructor."""
        super(PluginMapDefaultDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.lbl_info_url.linkActivated.connect(self.open_in_browser)
        # self.lbl_info_url.setTextInteractionFlags(Qt.TextSelectableByMouse)  # to make sure the user can copy/paste this uri
        self.combo_layer_fields.fieldChanged.connect(self.layer_field_changed)
        # self.le_default_value.textEdited.connect(self.default_value_edited)  # textEdited signal is only emitted in ui and programmatically
        self.le_default_value.textChanged.connect(self.default_value_edited)  # textChanged signal is BOTH emitted in ui AND when changed programmatically
        self.lbl_default_url.linkActivated.connect(self.open_in_browser)
        self.lbl_default_url.setTextInteractionFlags(Qt.TextSelectableByMouse)  # to make sure the user can copy/paste this uri
        self.record = None
        self.field = None
        self.connector = None

        self.search_code_dlg = PluginSearchCodeDialog(parent=self)
        self.search_code_dlg.setModal(True)
        self.search_code_dlg.setWindowModality(Qt.ApplicationModal)  # https://doc.qt.io/qt-5/qt.html#WindowModality-enum
        self.search_code_dlg.finished.connect(self.search_uri_finished)
        self.btn_search_api.clicked.connect(self.search_uri)

    @staticmethod
    def open_in_browser(link: str):
        QDesktopServices.openUrl(QUrl(link))

    def accept(self) -> None:
        """
        By Accepting the dialog you are actually SETTING the mapping
        """
        log.debug(f'OK, clicked {self}')
        data_field = self.combo_layer_fields.currentField()
        default = self.le_default_value.text()
        log.debug(f'Mapping of observation "{self.field}" set to data "{data_field}" with default: "{default}" in connector')
        if len(data_field) == 0:  # that is: an empty string: NO mapping
            self.connector.set_field_mapping(self.field, None)
        else:
            self.connector.set_field_mapping(self.field, data_field)
        if len(default) == 0:  # empty input: that is, user removed the uri or value from the input
            self.connector.set_field_default(self.field, None)
        else:
            # add the ndff-field->default to the defaults of the datasource
            self.connector.set_field_default(self.field, default)
            # just to be sure in case of value there is NO mapped data_field
            self.combo_layer_fields.setField('')
        # log.debug(f'Connector now: {self.connector}')
        self.done(QDialog.Accepted)

    def reject(self) -> None:
        log.debug(f'CANCEL, clicked {self}')
        self.done(QDialog.Rejected)

    def show(self, layer, connector: NdffConnector, record: dict, field: str) -> None:
        log.debug(f'Calling show of PluginMapDefaultDialog for layer: {layer} field: {field}')
        if layer is None or connector is None or field is None or field == '':
            # should not happen!
            raise NdffException(f'Calling PluginMapDefaultDialog with some None value: \nlayer: {layer} \nfield: {field} \nconnector: {connector} \nrecord: {record}')
        self.connector = connector
        self.record = record
        self.field = field
        self.combo_layer_fields.setLayer(layer)
        label = f' {connector.get_field_text(field)} ({connector.get_field_ndff_name(field)})'
        default_label = ''
        if connector.get_field_url2(field):
            default_label = f'{connector.get_field_url2(field)}'
        info_label = ''
        if connector.get_field_url1(field) and len(connector.get_field_url1(field)) > 15:
            f'Zie: <a href="{connector.get_field_url1(field)}">{connector.get_field_ndff_name(field)} in NDFF-woordenboek</a>'
        description_label = f'<i>{connector.get_field_description(field)}</i>'

        if field in ('identity', 'location_buffer', 'period_start', 'period_stop'):
            # search_default_group
            self.btn_search_api.setEnabled(False)
        else:
            self.btn_search_api.setEnabled(True)

        self.lbl_field.setText(f'{label}')
        self.lbl_info_url.setText(f'{info_label}')
        self.lbl_default_url.setText(f'{default_label}')
        self.lbl_description.setText(f'{description_label}')

        mapped_to = connector.get_field_mapping(field)

        if connector.get_field_default(field):
            self.le_default_value.setText(f'{connector.get_field_default(field)}')
        else:
            self.le_default_value.setText('')

            # PRESETTING THE DIALOG
            if mapped_to in self.record.keys():  # TODO self.data_record: NO: plugin should not keep administration of that!
                self.combo_layer_fields.setField(mapped_to)
                self.lbl_example_value.setText(f'{self.record[mapped_to]}')
            elif field in self.record.keys():
                # IF field is field in the record, preset it...
                self.combo_layer_fields.setField(field)
                self.lbl_example_value.setText(f'{self.record[field]}')
            else:
                self.combo_layer_fields.setField('')
                self.lbl_example_value.setText('')

        self.showNormal()

    def layer_field_changed(self, data_field: str):
        """
        Setting the dropdown AND the example from data based on a field/attribute from a data record

        So observation_field here is a data attribute
        """
        # show if there is a mapping for field = SET dropdown value AND the corresponding data if a record is available
        log.debug(f'Calling layer_field_changed for data field {data_field}')
        example_label = ''
        if data_field != '' and self.record and self.record[data_field]:
            example_label = self.record[data_field]  # TODO value <=> key ???
            # and cleanup the default value field
            self.le_default_value.setText('')
        self.lbl_example_value.setText(f'{example_label}')

    def default_value_edited(self, default_text: str):
        if default_text != '':
            # if a default field is defined, let's make the field dropdown empty
            self.combo_layer_fields.setField('')

    def search_uri_finished(self):
        default_uri = self.search_code_dlg.le_selected_uri.text()
        self.le_default_value.setText(default_uri)

    def search_uri(self):
        """
        Going to search for a NDFF uri or code/name/description for this field.

        Either a free name search (like 'man' for sex-field will search for 'man' to find an uri):
            https://accapi.ndff.nl/codes/v2/sexes/?name=man
        OR the other way around: search for description or terms based on the ndff uri
            https://accapi.ndff.nl/codes/v2/sexes/?identity=http://ndff-ecogrid.nl/codes/domainvalues/observation/sexes/undefined

        Note that if searching uri/codes for abundance_value, we have to take the (hopefully already set)
        abundance_SCHEMA. That is: if the schema is Tansley (which has special Tansley related VALUE codes), searching
        for or setting a default VALUE, you have to search in the resources which are mentioned in the Tansley
        resource in 'related_codes'...
        """
        search_for_text = self.le_default_value.text()
        if search_for_text == '':
            # first see if there was data for this field (is shown in self.lbl_example_value.text()
            if self.lbl_example_value.text() not in ('', None, ' ', '-'):
                search_for_text = self.lbl_example_value.text()
            else:
                # try lbl_default_url (which is the 'undefined' uri, defined in client_settings.csv)
                search_for_text = self.lbl_default_url.text()

        abundance_schema_uri = None
        if self.field == 'abundance_value':
            # OK, the user clicked on the 'abundance_value' button. it IS possible that current 'abundance_schema'
            # has 'related_codes', IF that is the case, we are going to search for them...
            # We do not have the actual observation here, only the record and connector, so map to observation via those:
            observation = self.connector.map_data_to_ndff_observation(self.record)
            abundance_schema_uri = observation.get('abundance_schema')
            # ONLY open the search dialog with related uri's if the abundance_schema has related codes...
            if self.connector.identity_has_related_codes(abundance_schema_uri):
                # then do NOT use the (default/example) value to search, nor the value from the record
                # it seems better to just show ALL related codes (instead of just one based on the current record value)
                # search_for_text = ''
                pass
            else:
                # make sure to NOT use the abundance schema uri. WITH an abundance_schema_uri we will try to find
                # related codes!!
                abundance_schema_uri = None

        description_string = f'Zoek Een Standaard URI voor het veld {self.connector.get_field_text(self.field)}'
        self.search_code_dlg.setup_gui(self.connector, self.field, search_value=search_for_text,
                                       abundance_schema_uri=abundance_schema_uri, description_string=description_string)

        self.search_code_dlg.open()
