# -*- coding: utf-8 -*-
"""
/***************************************************************************
 LfbRegenerationWildlifeImpactDialog
                                 A QGIS plugin
 Lfb Regeneration and Wildlife Impact Monitoring
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2023-05-08
        git sha              : $Format:%H$
        copyright            : (C) 2023 by Grünecho
        email                : support@grunecho.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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
import uuid
import json
import tempfile

from qgis.core import QgsMessageLog, QgsProject, QgsWkbTypes, QgsVectorFileWriter, QgsFeature, QgsGeometry, QgsPointXY, QgsVectorLayer, Qgis # Added QgsVectorLayer, Qgis
from qgis.PyQt import QtWidgets, uic
from qgis.PyQt.QtWidgets import QDialog
from qgis.PyQt.QtCore import QDateTime

#from PyQt5.uic import loadUi
from PyQt5 import QtCore

from ...utils.helper import Utils
from ..authentication import Authentication
from ..synchronization import Synchronization

#from .multi_change import MultiChange


UI_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'io_btn.ui'))


class IoBtn(QtWidgets.QWidget, UI_CLASS):
    """Implementation of the IoBtn widget."""

    exported = QtCore.pyqtSignal(bool)
    imported = QtCore.pyqtSignal(bool)
    importSelected = QtCore.pyqtSignal(bool)
    token_changed = QtCore.pyqtSignal(str)

    def __init__(self, interface):
        """Constructor."""

        QDialog.__init__(self, interface.mainWindow())

        self.setupUi(self)

        self.token = None
        self.email = ""

        self.fieldsToBeMapped = ['los_id', 'created', 'modified', 'workflow', 'status', 'form', 'losnr', 'los_id_impex', 'unterlosnr']

        self.lfbExportBtn.clicked.connect(self.exportBtnClicked)
        self.lfbImportBtn.clicked.connect(self.importBtnClicked)
        self.lfbImportSelectedBtn.clicked.connect(self.importSelectedBtnClicked)

        self.lfb_auth_btn.clicked.connect(self.authBtnClicked)
        self.lfb_sync_btn.clicked.connect(self.upload_data)
        self.lfb_sync_btn.hide()

        self.lfb_error_hide_btn.clicked.connect(self.lfb_error_wrapper.hide)

        self.exportLength = 0

        self.interface = interface

        self.lfbExportFeedback.setText('')
        self.lfb_error_wrapper.hide()

        self.exportOptions = QgsVectorFileWriter.SaveVectorOptions()
        self.exportOptions.driverName = 'GeoJson'
        self.exportOptions.includeZ = False
        self.exportOptions.overrideGeometryType = QgsWkbTypes.Point
        self.exportOptions.layerName = 'FIM - Forest Inventory and Monitoring'

        self.show()

        self.synchronization = Synchronization( self.interface )
        self.synchronization.geojson_received.connect(self.add_geojson_to_layer)
        self.synchronization.geojson_sent.connect(self.setFeedback)
        self.synchronization.update_list.connect(self.done_imported)
        self.synchronization.upload_success.connect(self.download_data)

        # Connect selection changed signal for the FIM layer
        fim_layer_name = self.exportOptions.layerName
        project_layers = QgsProject.instance().mapLayers().values()

        for layer in project_layers:
            if isinstance(layer, QgsVectorLayer):
                # Check if the layer is a point layer
                is_point_layer = layer.geometryType() == QgsWkbTypes.PointGeometry or \
                                 (layer.wkbType() & QgsWkbTypes.Point) == QgsWkbTypes.Point # Handles multi-part points as well

                if layer.name() == fim_layer_name:
                    if is_point_layer: # Ensure FIM layer is also point type before connecting
                        try:
                            layer.selectionChanged.connect(self.update)
                        except Exception as e:
                            QgsMessageLog.logMessage(f"Error connecting selectionChanged for FIM layer {layer.name()}: {e}", 'FIM', level=Qgis.Critical)
                    else:
                        QgsMessageLog.logMessage(f"FIM layer '{layer.name()}' is not a point layer. Cannot connect selectionChanged.", 'FIM', level=Qgis.Warning)
                elif is_point_layer:
                    try:
                        # Connect signal for other point layers
                        layer.selectionChanged.connect(self.update)
                    except Exception as e:
                        QgsMessageLog.logMessage(f"Error connecting selectionChanged for point layer {layer.name()}: {e}", 'FIM', level=Qgis.Critical)

        # Initial call to set button state based on current selection (if any)
        self.update()


    def done_imported(self):
        """Done imported."""
        self.imported.emit(True)

    def update(self):
        """Update the widget."""

        QgsMessageLog.logMessage('Update IoBtn', 'FIM')
        
        selectedFeatures  = Utils.getSelectedFeatures(self.interface, 'FIM - Forest Inventory and Monitoring')

        if len(selectedFeatures) > 0:
            self.lfbImportSelectedBtn.setEnabled(True)
            self.lfbImportSelectedBtn.setText('IMPORTIERE AUSGEWÄHLTE PUNKTE')
        else:
            self.lfbImportSelectedBtn.setText('IMPORTIERE AUSGEWÄHLTE PUNKTE')
            self.lfbImportSelectedBtn.setEnabled(False)

        return selectedFeatures

    def setExportLength(self, length):
        """Set the export length."""
        self.exportLength = length

        if self.exportLength > 0:
            self.lfbExportBtn.setEnabled(True)
        else:
            self.lfbExportBtn.setEnabled(False)

    def setFeedback(self, feedback, error=False):
        """show feedback text."""

        self.lfbExportFeedback.setText(feedback)

        if error:
            self.lfbExportFeedback.setStyleSheet('color: red;')
        else:
            self.lfbExportFeedback.setStyleSheet('')

        self.lfb_error_wrapper.show()

    def importSelectedBtnClicked(self):
        """Import on click."""

        currentDateTime = QDateTime.currentDateTime()

        selectedFeatures  = Utils.getSelectedFeatures(self.interface, 'FIM - Forest Inventory and Monitoring', True)
        self.update()

        layer = Utils.getLayerById()
        if not layer:
            return
        fields = layer.fields()

        layer.startEditing()

        defaultJson = Utils.loadDefaultJson()
        
        for selectedLayer in selectedFeatures:
            for feature in selectedLayer['features']:

                geom = feature.geometry()
                coordinates = geom.asPoint()

                #attrs = i.attributeMap()
                layerFields = selectedLayer['layer'].fields()
                attributes = feature.attributes()
                defaultAttributes = {
                    'los_id': str(uuid.uuid4()),
                    'created': currentDateTime,
                    'modified': currentDateTime,
                    'workflow': 4,
                    'status': False,
                    'form': json.dumps(defaultJson['properties']),
                    'losnr': '',
                    'los_id_impex': None,
                    'unterlosnr': None
                }

                ## SAVE FEATURES
                qgsFeature = QgsFeature()
                qgsFeature.setFields(fields)
                geometry = QgsGeometry.fromPointXY(QgsPointXY(coordinates))
                qgsFeature.setGeometry(geometry)


                for fieldName in self.fieldsToBeMapped:
                    idx = layerFields.indexFromName(fieldName)
                    if idx >= 0 and attributes[idx]:
                        qgsFeature.setAttribute(fieldName, attributes[idx])
                    else:
                        qgsFeature.setAttribute(fieldName, defaultAttributes[fieldName])


                if hasattr(qgsFeature, 'los_id'):
                    qgsFeature.setAttribute('id', qgsFeature['los_id'])
                else:
                    qgsFeature.setAttribute('id', defaultAttributes['los_id'])


                layer.addFeature(qgsFeature)
                layer.removeSelection()

        layer.commitChanges()
        layer.endEditCommand()

        self.imported.emit(True)

    def importBtnClicked(self):
        """Open the file dialog and import the GeoJSON file to the layer."""

        fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Select File')

        if fileName:
            self.importFromFile(fileName)

    def importFromFile(self, fileName):
        """Import the GeoJSON file to the layer."""

        with open(fileName, 'r') as f:
            data = json.load(f)

        if not data:
            self.setFeedback('Fehler beim Import', True)
            return
        elif not 'features' in data:
            self.setFeedback('Fehler beim Import', True)
            return
        else:
            QgsMessageLog.logMessage('Importing data: ', 'FIM')
            self.add_geojson_to_layer(data)
            
    def add_geojson_to_layer(self, data):

        #if not data:
        #    QgsMessageLog.logMessage('No data to import', 'FIM')
        #    return

        if not data or 'features' not in data or data['features'] is None or len(data['features']) == 0:
            QgsMessageLog.logMessage('NO DATA', 'FIM')
            QgsMessageLog.logMessage(json.dumps(data), 'FIM')
            if len(data['features']) == 0:
                self.setFeedback('Keine zugewiesenen Punkte gefunden.', False)
            return

        layer = Utils.getLayerById()

        if not layer:
            self.setFeedback('Layer nicht gefunden', True)
            return

        layer.startEditing()

        currentDateTime = QDateTime.currentDateTime()

        fields = layer.fields()

        newFeaturesCount = 0
        for feature in data['features']:

            existingFeature = Utils.idNotUnique(layer, feature['properties']['los_id'])
            if existingFeature is not None:
                QgsMessageLog.logMessage('Feature already exists: ' + str(feature['properties']['los_id']), 'FIM')
                # Overwrite attribute 'unterlosnr' if it is not unique
                if 'unterlosnr' in feature['properties']:
                    existingFeature.setAttribute('unterlosnr', feature['properties']['unterlosnr'])
                    layer.updateFeature(existingFeature)

                continue
            
            qgsFeature = QgsFeature()
            qgsFeature.setFields(fields)
            geometry = QgsGeometry.fromPointXY(QgsPointXY(
                feature['geometry']['coordinates'][0], 
                feature['geometry']['coordinates'][1]
            ))
            qgsFeature.setGeometry(geometry)
            qgsFeature.setAttribute('created', currentDateTime)
            qgsFeature.setAttribute('modified', currentDateTime)


            for field in fields:
                name = field.displayName()
                if name in feature['properties']:
                    qgsFeature.setAttribute(name, feature['properties'][name])

            if 'properties' in feature:
                if 'form' in feature['properties']:
                    form_data = feature['properties']['form']
                    if isinstance(form_data, str):
                        form_data = json.loads(form_data)
                    qgsFeature.setAttribute('form', json.dumps(form_data))

            layer.addFeature(qgsFeature)
            newFeaturesCount += 1

        layer.commitChanges()

        self.setFeedback(str(newFeaturesCount) + ' Punkt(e) hinzugefügt')

        self.imported.emit(True)


    # Authentication AND SYNC
    def set_token(self, token):
        """Set the token."""

        self.token = token
        self.token_changed.emit(token)
        #self.multiChange.set_token(token)
        
    
        self.upload_data()

    def download_data(self, success = True):
        """Download data from the remote host."""
        if success == False:
            return
        
        QgsMessageLog.logMessage('DOWNLOAD data', 'FIM')
        
        layer = Utils.getLayerById()
        self.synchronization.add_geojson_from_host(layer, self.token)

    def upload_data(self):
        
            
        layer = Utils.getLayerById()

        # DOWNLOAD DATA FROM REMOTE HOST
        #self.synchronization.add_geojson_from_host(layer, self.token)
        #QgsMessageLog.logMessage('DOWNLOAD data', 'FIM')
        
        # UPLOAD
        with tempfile.NamedTemporaryFile(delete=False) as tmp:
            tmp_file = tmp.name
             
        errors = QgsVectorFileWriter.writeAsVectorFormatV3(
            layer=layer,
            fileName= tmp_file,
            transformContext=QgsProject.instance().transformContext(),
            options=self.exportOptions
        )

        # Step 4: Read the temporary GeoJSON file
        with open(tmp_file, 'r', encoding="UTF-8") as file:
            geojson = json.load(file)
            for feature in geojson['features']:
                if feature['properties']['status'] == False:
                    geojson['features'].remove(feature)
                elif feature['properties']['workflow'] != 5 and feature['properties']['workflow'] != 9 and feature['properties']['workflow'] != 22:
                    geojson['features'].remove(feature)
        
        # Clean up the temporary file
        os.remove(tmp_file)

        # UPLOAD DATA TO REMOTE HOST
        QgsMessageLog.logMessage('UPLOAD data', 'FIM')
        self.synchronization.send_geojson_to_host(geojson, self.token)

    def set_email(self, email):
        """Set the email."""

        self.email = email

    def authBtnClicked(self):
        """Open the authentication dialog."""

        dialog = Authentication(None, self.email)
        dialog.token_changed.connect(self.set_token)
        dialog.set_email.connect(self.set_email)

        #dialog.ui = Authentication()
        #dialog.ui.setupUi(dialog)
        #dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        dialog.exec_()

    def exportBtnClicked(self):
        """Check if folder exists and export the layer to a GeoJSON file."""

        folder = QtWidgets.QFileDialog.getExistingDirectory(self, 'Select Folder')
        
        if folder:
            self.exportToFolder(folder)

    def exportToFolder(self, folder):
        """Export the layer to a GeoJSON file."""

        currentDateTime = QDateTime.currentDateTime()
        fileName = folder + '/FIM-' + currentDateTime.toString("yyyy-M-d_hh-mm") + '.geojson'

        layer = Utils.getLayerById()

        if not layer:
            self.setFeedback('Layer nicht gefunden', True)
            return
        
        try:
            res = QgsVectorFileWriter.writeAsVectorFormatV3(
                layer,
                fileName,
                QgsProject.instance().transformContext(),
                self.exportOptions
            )
        except Exception as e:
            self.setFeedback('Fehler beim Export', True)
            return

        #self.lfbExportFeedback.setText('letzte Export: ' + fileName)
        self.setFeedback('Erfolgreich Exportiert: ' + fileName, False)
        #self.exported.emit(True)