# -*- coding: utf-8 -*-

# qdrawEVT: plugin that makes drawing easier
# Author: Jérémy Kalsron
#         jeremy.kalsron@gmail.com
#
# 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 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import random
import unicodedata
from builtins import str

from qgis.PyQt.QtCore import Qt, QCoreApplication, pyqtSignal, QVariant
from qgis.PyQt.QtCore import Qt as QtCoreQt  # Ajout pour compatibilité Qt6
from qgis.PyQt.QtGui import QColor, QFont, QGuiApplication
from qgis.PyQt.QtWidgets import QWidget, QPushButton, QSlider, \
    QLabel, QColorDialog, QVBoxLayout, QFontDialog, QMessageBox

from qgis.PyQt.QtCore import PYQT_VERSION_STR as pyqt_version  # Importer la version de PyQt
if pyqt_version.startswith("5"):
    pyqt_messagebox_question = QMessageBox.Question
    pyqt_messagebox_critical = QMessageBox.Critical
    pyqt_messagebox_warning = QMessageBox.Warning
    pyqt_messagebox_information = QMessageBox.Information
    yes_button = QMessageBox.Yes
    no_button = QMessageBox.No
    pyqt_messagebox_cancel = QMessageBox.Cancel
    qt_windows_modality = Qt.WindowModal
    qt_application_modal = Qt.ApplicationModal
    qt_window_stays_on_top_hint = Qt.WindowStaysOnTopHint
elif pyqt_version.startswith("6"):
    pyqt_messagebox_question = QMessageBox.Icon.Question
    pyqt_messagebox_critical = QMessageBox.Icon.Critical
    pyqt_messagebox_warning = QMessageBox.Icon.Warning
    pyqt_messagebox_information = QMessageBox.Icon.Information
    yes_button = QMessageBox.StandardButton.Yes
    no_button = QMessageBox.StandardButton.No
    pyqt_messagebox_cancel = QMessageBox.StandardButton.Cancel
    qt_windows_modality = Qt.WindowModality.WindowModal
    qt_application_modal = Qt.WindowModality.ApplicationModal
    qt_window_stays_on_top_hint = Qt.WindowType.WindowStaysOnTopHint

from qgis.core import *
from qgis.core import QgsSettings, QgsProject, QgsVectorLayer, QgsVectorFileWriter, \
    QgsWkbTypes, QgsField, QgsFields, QgsLayerTree, QgsApplication, QgsLayerTreeLayer
from qgis.utils import iface
from pathlib import Path
import unicodedata
from . import resources
from .logger import log


class QdrawSettings(QWidget):
    """Window used to change settings (transparency/color/event layers/layers path)"""
    settingsChanged = pyqtSignal()

    def __init__(self, form_wgt_libelle, iface):
        super().__init__()

        self.form_wgt_libelle = form_wgt_libelle
        self.iface = iface
        from .logger import redirect_print_to_log
        redirect_print_to_log()
        self.project = QgsProject.instance()

        self.setWindowTitle(self.tr('QdrawEVT - Settings'))
        self.setFixedSize(400, 180)
        self.center()
        self.keepselect = False

        # Chargement des préférences utilisateur
        self.restore_settings()

        # Slider d’opacité
        self.sld_opacity = QSlider(QtCoreQt.Orientation.Horizontal, self)
        self.sld_opacity.setRange(0, 255)
        self.sld_opacity.setValue(self.color.alpha())
        self.sld_opacity.valueChanged.connect(self.handler_opacitySliderValue)
        self.lbl_opacity = QLabel(f"{self.tr('Opacity')}: {int(self.color.alpha()/2.55)}%", self)

        # Boutons de paramétrage
        self.dlg_color = QColorDialog(self)
        self.btn_chColor = QPushButton(self.tr('Change the drawing color'), self)
        self.btn_chColor.clicked.connect(self.handler_chColor)

        self.dlg_font = QFontDialog(self)
        self.btn_chFont = QPushButton(self.tr('Change text font'), self)
        self.btn_chFont.clicked.connect(self.handler_chFont)

        self.dlg_colorFont = QColorDialog(self)
        self.btn_chColorFont = QPushButton(self.tr('Change text color'), self)
        self.btn_chColorFont.clicked.connect(self.handler_chColorFont)

        self.btn_createLayers = QPushButton(self.tr('Create the group and the event layers'), self)
        self.btn_createLayers.clicked.connect(self.handler_createLayers)

        # Mise en page
        vbox = QVBoxLayout()
        vbox.addWidget(self.lbl_opacity)
        vbox.addWidget(self.sld_opacity)
        vbox.addWidget(self.btn_chColor)
        vbox.addWidget(self.btn_chFont)
        vbox.addWidget(self.btn_chColorFont)
        vbox.addWidget(self.btn_createLayers)
        self.setLayout(vbox)

    # --- Traduction ---
    def tr(self, message):
        return QCoreApplication.translate('QdrawSettings', message)

    # --- Slider de transparence ---
    def handler_opacitySliderValue(self, val):
        try:
            self.color.setAlpha(val)
            self.lbl_opacity.setText(f"{self.tr('Opacity')}: {int(val/2.55)}%")
            self.save_settings()
            self.settingsChanged.emit()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans handler_opacitySliderValue : {e}", "QdrawEVT", Qgis.Warning)

    # --- Changement de couleur principale ---
    def handler_chColor(self):
        try:
            color = self.dlg_color.getColor(self.color)
            if color.isValid():
                color.setAlpha(self.color.alpha())
                self.color = color
                self.save_settings()
                self.settingsChanged.emit()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans handler_chColor : {e}", "QdrawEVT", Qgis.Warning)

    # --- Changement de police ---
    def handler_chFont(self):
        try:
            font, ok = self.dlg_font.getFont(self.font)
            if ok:
                self.font = font
                self.save_settings()
                self.settingsChanged.emit()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans handler_chFont : {e}", "QdrawEVT", Qgis.Warning)

    # --- Changement de couleur du texte ---
    def handler_chColorFont(self):
        try:
            color = self.dlg_colorFont.getColor(self.colorFont)
            if color.isValid():
                color.setAlpha(self.color.alpha())
                self.colorFont = color
                self.save_settings()
                self.settingsChanged.emit()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans handler_chColorFont : {e}", "QdrawEVT", Qgis.Warning)

    # --- Sauvegarde et restauration des paramètres ---
    def save_settings(self):
        try:
            settings = QgsSettings()
            settings.beginGroup("/Qdraw")
            settings.setValue("font", self.font.family())
            settings.setValue("fontSize", self.font.pointSize())
            settings.setValue("colorFontRed", self.colorFont.red())
            settings.setValue("colorFontGreen", self.colorFont.green())
            settings.setValue("colorFontBlue", self.colorFont.blue())
            settings.setValue("colorFontAlpha", self.colorFont.alpha())
            settings.setValue("colorRed", self.color.red())
            settings.setValue("colorGreen", self.color.green())
            settings.setValue("colorBlue", self.color.blue())
            settings.setValue("colorAlpha", self.color.alpha())
            settings.endGroup()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans save_settings : {e}", "QdrawEVT", Qgis.Warning)

    def restore_settings(self):
        try:
            settings = QgsSettings()
            settings.beginGroup("/Qdraw")
            self.font = QFont(settings.value("font", 'arial'),
                              int(settings.value("fontSize", 12)))
            self.colorFont = QColor(
                int(settings.value("colorFontRed", 0)),
                int(settings.value("colorFontGreen", 0)),
                int(settings.value("colorFontBlue", 0)),
                int(settings.value("colorFontAlpha", 255))
            )
            self.color = QColor(
                int(settings.value("colorRed", 60)),
                int(settings.value("colorGreen", 151)),
                int(settings.value("colorBlue", 255)),
                int(settings.value("colorAlpha", 255))
            )
            settings.endGroup()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans restore_settings : {e}", "QdrawEVT", Qgis.Warning)

    # --- Création des couches événement ---
    def handler_createLayers(self):
        try:
            project = QgsProject.instance()
            root = project.layerTreeRoot()
            evtpath = project.homePath()
            qmlpath = ':/plugins/qdrawEVT/resources/'

            if not project.fileName():
                QMessageBox.warning(
                    self.iface.mainWindow(),
                    self.tr("Creation of event shapefile"),
                    self.tr("Possible only in a saved project."),
                )
                return

            evt_folder = os.path.join(evtpath, "Evenements")
            os.makedirs(evt_folder, exist_ok=True)

            # Vérification si déjà présentes
            for shp in ["POLYGONE_EVENEMENT.shp", "LIGNE_EVENEMENT.shp", "POINT_EVENEMENT.shp"]:
                if os.path.isfile(os.path.join(evt_folder, shp)):
                    QgsMessageLog.logMessage(f"{shp} déjà existante.", "QdrawEVT", Qgis.Info)

            groupevt = None
            for group in root.children():
                test = ''.join(
                    x for x in unicodedata.normalize('NFKD', group.name())
                    if unicodedata.category(x)[0] == 'L'
                ).upper()
                if test == 'EVENEMENTS':
                    groupevt = group
                    break

            if groupevt is None:
                groupevt = root.insertGroup(0, 'Evenements')

            # Création ou chargement des shapefiles
            lstlayerEVT = []
            crs = project.crs()
            transform_context = project.transformContext()
            save_options = QgsVectorFileWriter.SaveVectorOptions()
            save_options.driverName = "ESRI Shapefile"
            save_options.fileEncoding = "UTF-8"

            # POLYGONE
            poly_path = os.path.join(evt_folder, "POLYGONE_EVENEMENT.shp")
            if not os.path.isfile(poly_path):
                fields = QgsFields()
                for n in ['libelle', 'date', 'h_creation', 'source', 'h_constat', 'remarques', 'surface', 'utilisatr']:
                    ftype = QVariant.Double if n == 'surface' else QVariant.String
                    fields.append(QgsField(n, ftype))
                lstlayerEVT.append((poly_path, fields, QgsWkbTypes.MultiPolygon, qmlpath + 'POLYGONE_EVENEMENT.qml'))

            # LIGNE
            line_path = os.path.join(evt_folder, "LIGNE_EVENEMENT.shp")
            if not os.path.isfile(line_path):
                fields = QgsFields()
                for n in ['libelle', 'date', 'h_creation', 'source', 'h_constat', 'remarques', 'longueur', 'utilisatr']:
                    ftype = QVariant.Double if n == 'longueur' else QVariant.String
                    fields.append(QgsField(n, ftype))
                lstlayerEVT.append((line_path, fields, QgsWkbTypes.MultiLineString, qmlpath + 'LIGNE_EVENEMENT.qml'))

            # POINT
            point_path = os.path.join(evt_folder, "POINT_EVENEMENT.shp")
            if not os.path.isfile(point_path):
                fields = QgsFields()
                for n in ['libelle', 'date', 'h_creation', 'source', 'h_constat', 'remarques', 'x_gps', 'y_gps', 'utilisatr']:
                    ftype = QVariant.Double if n in ('x_gps', 'y_gps') else QVariant.String
                    fields.append(QgsField(n, ftype))
                lstlayerEVT.append((point_path, fields, QgsWkbTypes.MultiPoint, qmlpath + 'POINT_EVENEMENT.qml'))

            # Écriture des shapefiles
            for layer in lstlayerEVT:
                writer = QgsVectorFileWriter.create(
                    layer[0], layer[1], layer[2], crs, transform_context, save_options
                )
                if writer.hasError() != QgsVectorFileWriter.NoError:
                    QMessageBox.critical(
                        self.iface.mainWindow(),
                        self.tr("Error when creating shapefile"),
                        writer.errorMessage(),
                    )
                    continue
                del writer

                vlayer = QgsVectorLayer(layer[0], os.path.basename(layer[0]).split(".")[0], "ogr")
                if not vlayer.isValid():
                    QgsMessageLog.logMessage(f"Erreur : couche {layer[0]} invalide.", "QdrawEVT", Qgis.Critical)
                    continue

                vlayer.loadNamedStyle(layer[3])
                self.project.addMapLayer(vlayer)
                node = root.findLayer(vlayer.id())
                if node:
                    clone = node.clone()
                    groupevt.insertChildNode(0, clone)
                    node.parent().removeChildNode(node)
                vlayer.setReadOnly(True)
                vlayer.triggerRepaint()

            self.btn_createLayers.setEnabled(False)
            self.close()
        except Exception as e:
            QgsMessageLog.logMessage(f"Erreur dans handler_createLayers : {e}", "QdrawEVT", Qgis.Critical)
            QMessageBox.critical(self.iface.mainWindow(), "QdrawEVT", f"Erreur : {e}")

    def center(self):
        screen = QGuiApplication.primaryScreen().geometry()
        size = self.geometry()
        self.move(
            int((screen.width() - size.width()) / 2),
            int((screen.height() - size.height()) / 2)
        )

    # --- Méthodes d'accès pour compatibilité avec le code principal ---
    def getColor(self):
        """Renvoie la couleur de dessin actuelle."""
        try:
            return self.color
        except AttributeError:
            QgsMessageLog.logMessage("Attribut color introuvable dans QdrawSettings", "QdrawEVT", Qgis.Warning)
            return QColor(0, 0, 0, 255)

    def getFont(self):
        """Renvoie la police utilisée pour le texte."""
        try:
            return self.font
        except AttributeError:
            QgsMessageLog.logMessage("Attribut font introuvable dans QdrawSettings", "QdrawEVT", Qgis.Warning)
            return QFont('Arial', 12)

    def getColorFont(self):
        """Renvoie la couleur du texte."""
        try:
            return self.colorFont
        except AttributeError:
            QgsMessageLog.logMessage("Attribut colorFont introuvable dans QdrawSettings", "QdrawEVT", Qgis.Warning)
            return QColor(0, 0, 0, 255)

    def getOpacity(self):
        """Renvoie l'opacité actuelle (0-255)."""
        try:
            return self.color.alpha()
        except AttributeError:
            QgsMessageLog.logMessage("Attribut color introuvable pour getOpacity", "QdrawEVT", Qgis.Warning)
            return 255