import json
from PyQt5.QtWidgets import QDialog, QMessageBox, QDialogButtonBox, QProgressDialog, QApplication, QCompleter,QPushButton
from PyQt5.QtGui import QStandardItem, QStandardItemModel  # Correct import
from PyQt5.uic import loadUi
from qgis.core import QgsProject
from PyQt5.QtCore import Qt, QTimer,QStringListModel  # Ajout de l'importation de QtCore
from PyQt5 import uic
from PyQt5.QtWidgets import *
import os
import time  # Utilisé pour simuler un traitement long
import urllib.request

# Dossier cache local
ui_cache_dir = os.path.join(os.path.expanduser("~"), "qgis_ui_cache")
os.makedirs(ui_cache_dir, exist_ok=True)

# URL de base
base_url = "https://symbols.sde03.fr/qgis/ui/"

ui_file = "action-data-nouveau-prise.ui"

ui_path = os.path.join(ui_cache_dir, ui_file)

# Télécharger si nécessaire
if not os.path.exists(ui_path):
    urllib.request.urlretrieve(base_url + ui_file, ui_path)

# Charger le UI
#uic.loadUi(local_ui_path, self)




# Définissez le chemin du fichier .ui
#ui_path = r"P:/Informatique/Cartographie/Projets QGis/Forms/action-data-nouveau-prise.ui"

# Créer une instance de QDialog
dialog = QDialog()

# Variable contenant les nouvelles données
data = None

# Définition des variables
items_code_marque = {}
items_code_reference_prise = {}
items_code_couleur = {}

#Initialisation des Completer
completer_prise_code_marque = QCompleter()
completer_prise_code_reference_prise = QCompleter()
completer_prise_code_couleur = QCompleter()


# Charger les couches nécessaires
layer_marque = QgsProject.instance().mapLayersByName("Marques")[0]
layer_reference_prise = QgsProject.instance().mapLayersByName("Références prise")[0]
layer_couleur = QgsProject.instance().mapLayersByName("Couleurs")[0]

def initData():
    global data
    data = {}
    data['prise'] = {}


#######################################################################################################################################################################################################
#   Fonctions pour initialisaer les Completer
#######################################################################################################################################################################################################

"""Initialisation des marques de prise"""
def init_prise_code_marque(dialog, data):
    global completer_prise_code_marque

    # Récupération des données dans la couche
    for feature in layer_marque.getFeatures():
        code = feature["code"]
        libelle = feature["libelle"]
        display_text = f"{libelle}" if libelle else code
        items_code_marque[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_marque.keys()))

    # Alimentation du QCompleter pour l'autocomplétion
    #completer_prise_code_marque = QCompleter(list(items_code_marque.keys()))
    completer_prise_code_marque.setModel(model)
    completer_prise_code_marque.setCaseSensitivity(Qt.CaseInsensitive)
    completer_prise_code_marque.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_prise_code_marque.setCompleter(completer_prise_code_marque)


"""Initialisation des références de prise"""
def init_prise_code_reference_prise(dialog, data):
    global completer_prise_code_reference_prise

    # Vider le tableau pour chaque mise à jour
    items_code_reference_prise.clear()  

    # Récupération des données dans la couche
    for feature in layer_reference_prise.getFeatures():
        if 'code_marque' in data :
            if feature["code_marque"] == data['code_marque'] :
                code = feature["code_path"]
                libelle = feature["libelle_path"]
                display_text = f"{libelle}" if libelle else code
                items_code_reference_prise[display_text] = code
        else :
            print(repr(feature["code_marque"]))
            if repr(feature["code_marque"])== 'NULL':
                code = feature["code_path"]
                libelle = feature["libelle_path"]
                display_text = f"{libelle}" if libelle else code
                items_code_reference_prise[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_reference_prise.keys()))

    # Alimentation du QCompleter pour l'autocomplétion
    completer_prise_code_reference_prise.setModel(model)
    completer_prise_code_reference_prise.setCaseSensitivity(Qt.CaseInsensitive)
    completer_prise_code_reference_prise.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_prise_code_reference_prise.setCompleter(completer_prise_code_reference_prise)


"""Initialisation des couleur de prise"""
def init_prise_code_couleur(dialog, data):
    global completer_prise_code_couleur

    # Vider le tableau pour chaque mise à jour
    items_code_couleur.clear()  

    # Récupération des données dans la couche
    for feature in layer_couleur.getFeatures():
        if feature["nature"] == data['nature_couleur'] :
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_couleur[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_couleur.keys()))

    # Alimentation du QCompleter pour l'autocomplétion
    completer_prise_code_couleur.setModel(model)
    completer_prise_code_couleur.setCaseSensitivity(Qt.CaseInsensitive)
    completer_prise_code_couleur.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_prise_code_couleur.setCompleter(completer_prise_code_couleur)


#######################################################################################################################################################################################################
#   Fonctions pour les Update
#######################################################################################################################################################################################################

""" LES PRISES """

# Marque
def update_prise_code_marque():
    # Récupération de la valeur du code
    data['prise']['code_marque'] = items_code_marque.get(dialog.nouveau_prise_code_marque.text())
    # MAJ Champ enfant lié
    init_prise_code_reference_prise(dialog, data['prise'])
    # Donne le focus sur le champ enfant
    dialog.nouveau_prise_code_reference_prise.setFocus()

# Référence
def update_prise_code_reference_prise():
    # Récupération de la valeur du code
    data['prise']['code_reference_prise'] = items_code_reference_prise.get(dialog.nouveau_prise_code_reference_prise.text())

# Nature couleur
def update_prise_nature_couleur(checked, param_name):
    if checked:
        data['prise']['nature_couleur'] = param_name
    # MAJ Champ enfant lié
    init_prise_code_couleur(dialog, data['prise'])
    # Donne le focus sur le champ enfant
    dialog.nouveau_prise_code_couleur.setFocus()
    # Nettoyage de la clé dans Data
    data['prise'].pop('code_couleur', None)           
    # Donne le focus sur le champ
    dialog.nouveau_prise_code_couleur.clear(),  # Vider le champ

# Code couleur
def update_prise_code_couleur():
    # Récupération de la valeur du code
    data['prise']['code_couleur'] = items_code_couleur.get(dialog.nouveau_prise_code_couleur.text())



#######################################################################################################################################################################################################
#   Fonctions pour les Coller les Data
#######################################################################################################################################################################################################

""" PRISES """

def pasteDataPrise(dialog):
    # Lire une propriété personnalisée
    value, found = QgsProject.instance().readEntry("MyGroup", "data")
    if found:
        # Récupération de la chaine de caractères au format JSON
        data = json.loads(value)

        # Marque
        for display_text, code in items_code_marque.items():
            if code == data.get('nouveau', {}).get('prise', {}).get('code_marque', ''):
                dialog.nouveau_prise_code_marque.setText(display_text)
                init_prise_code_reference_prise(dialog, data.get('nouveau', {}).get('prise', {}))
                update_prise_code_marque()
                break

        # Référence
        for display_text, code in items_code_reference_prise.items():
            if code == data.get('nouveau', {}).get('prise', {}).get('code_reference_prise', ''):
                dialog.nouveau_prise_code_reference_prise.setText(display_text)
                update_prise_code_reference_prise()
                break

        # Nature de la couleur
        if (data.get('nouveau', {}).get('prise', {}).get('nature_couleur', '')) == "Ral":
            dialog.nouveau_prise_nature_couleur_ral.setChecked(True)
        elif (data.get('nouveau', {}).get('prise', {}).get('nature_couleur', '')) == "Akzo":
            dialog.nouveau_prise_nature_couleur_akzo.setChecked(True)
        elif (data.get('nouveau', {}).get('prise', {}).get('nature_couleur', '')) == "Sublimation":
            dialog.nouveau_prise_nature_couleur_sublimation.setChecked(True)

        # Couleur
        for display_text, code in items_code_couleur.items():
            if code == data.get('nouveau', {}).get('prise', {}).get('code_couleur', ''):
                dialog.nouveau_prise_code_couleur.setText(display_text)
                update_prise_code_couleur()
                break
    else:
        print("Propriété non trouvée, valeur par défaut utilisée.")



#######################################################################################################################################################################################################
#  Exécution du traitement
#######################################################################################################################################################################################################


def execution(iface, formulaire, data):
    try:
        # Couche de noeuds
        layer_noeuds = QgsProject.instance().mapLayersByName("Noeuds Prises")[0]

        # Récupérer les entités sélectionnées
        selected_features = layer_noeuds.selectedFeatures()

        if len(selected_features) == 0 :
            QMessageBox.warning(None, "Avertissement", "Aucun élément sélectionné !")
            return

        # Créer la fenêtre de progression
        progress = QProgressDialog("Traitement en cours...", "Annuler", 0, 100, iface.mainWindow())
        progress.setWindowModality(Qt.WindowModal)  # Utiliser Qt.WindowModal
        progress.setCancelButton(None)  # Désactiver le bouton annuler si nécessaire
        progress.setRange(0, 100)
        progress.setValue(0)
        progress.setLabelText("Mise à jour en cours...")
        progress.show()

        # Démarrer l'édition de la couche
        if not layer_noeuds.isEditable():
            layer_noeuds.startEditing()

        # Calcul de l'incrément pour la barre de progression
        increment = int(100 / len(selected_features))

        # Boucle pour traiter toutes les entités
        for feature in selected_features:
            #On fait évoluer la barre de progression
            progress.setValue(progress.value() + increment)
            QApplication.processEvents()  # Permet de garder l'interface réactive
        
            if feature['data'] is None:
                feature['data'] = {
                    'existant': {},
                    'nouveau': {}
                }

            existingData = feature['data']
            
            if 'prise' not in existingData['nouveau'] :
                existingData['nouveau']['prise'] = {}                
            existingData['nouveau']['prise'].update(data['prise'])

            # Modifier
            feature.setAttribute('data',  existingData)

            #Validation de la modification
            layer_noeuds.updateFeature(feature)

        # Valider les modifications
        #layer_noeuds.commitChanges()

        # Désactiver la sélection
        #layer_noeuds.removeSelection()

        # Fermer la fenêtre d'attente une fois le traitement terminé
        progress.setValue(100)
        progress.hide()

        # Afficher un message de confirmation
        QMessageBox.information(None, "Succès", "Le traitement est terminé avec succès !")

        # Fermer le formulaire
        formulaire.close()
        
    except Exception as e:
        QMessageBox.critical(None, "Erreur", f"Une erreur est survenue : {e}")



#######################################################################################################################################################################################################
#  Création du formulaire
#######################################################################################################################################################################################################

def formulaire(iface):
    global dialog
    global data
    try:        
        # Charger le fichier .ui dans le QDialog
        loadUi(ui_path, dialog)
        
        initData()
        

        """ BOUTONS """

        #Bouton pour coller les Datas Prise
        dialog.findChild(QPushButton, "btn_paste_prise").setEnabled(True)
        dialog.findChild(QPushButton, "btn_paste_prise").clicked.connect(
            lambda: pasteDataPrise(dialog)
        )

        """ MARQUE DES PRISES """

        init_prise_code_marque(dialog, data['prise'])

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_prise_code_marque.activated.connect(update_prise_code_marque)      

        # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_marque_prise`
        dialog.nouveau_prise_code_marque.textChanged.connect(lambda: (
            dialog.nouveau_prise_code_reference_prise.clear(),  # Vider le champ enfant
            init_prise_code_reference_prise(dialog, {}),
            data['prise'].pop('code_reference_prise', None)  # Supprimer la clé de `data`
        ))

        """ REFERENCE PRISES """

        init_prise_code_reference_prise(dialog, data['prise'])

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_prise_code_reference_prise.activated.connect(update_prise_code_reference_prise)


        """ NATURE COULEUR """

        # Détection changement de valeur
        dialog.nouveau_prise_nature_couleur_ral.toggled.connect(lambda checked: update_prise_nature_couleur(checked, "Ral"))
        dialog.nouveau_prise_nature_couleur_akzo.toggled.connect(lambda checked: update_prise_nature_couleur(checked, "Akzo"))
        dialog.nouveau_prise_nature_couleur_sublimation.toggled.connect(lambda checked: update_prise_nature_couleur(checked, "Sublimation"))


        """ CODE COULEUR """

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_prise_code_couleur.activated.connect(update_prise_code_couleur)


        

        


        """ GESTION DES BOUTON DE LA DIALOG BOX """

        # Gérer les boutons
        button_box = dialog.findChild(QDialogButtonBox, "buttonBox")

        if button_box:
            def on_accept():
                # Vérifier si le code_armoire est vide
                # if 'code_reference_prise' not in data['prise'] or data['prise']['code_reference_prise'] == '':
                #    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir une référence prise")
                #    return

                # On exécute le traitement en renvoyant les datas
                execution(iface, dialog, data)

            # Connecter le bouton "OK"
            button_box.accepted.disconnect()  # Supprimer la connexion pour empecher la fermeture automatique du formulaire
            button_box.accepted.connect(on_accept)  # Connecter le gestionnaire à la place
            button_box.rejected.connect(dialog.reject)

        dialog.exec_()

    except Exception as e:
        # Gérer les erreurs
        QMessageBox.critical(None, "Erreur", f"Impossible d'ouvrir le formulaire : {e}")
