from PyQt5.QtWidgets import QDialog, QMessageBox, QDialogButtonBox, QProgressDialog, QApplication, QCompleter
from PyQt5.QtGui import QStandardItem, QStandardItemModel  # Correct import
from PyQt5.uic import loadUi
from qgis.core import QgsProject
from PyQt5.QtCore import Qt, QTimer  # 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-raccordement-nouveau-noeud.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-raccordement-nouveau-noeud.ui"

def execution(iface, formulaire, data):
    try:
        # Couche de noeuds
        layer_luminaires = QgsProject.instance().mapLayersByName("Noeuds Luminaires")[0]

         # Couche de prises
        layer_prises = QgsProject.instance().mapLayersByName("Noeuds Prises")[0]

        # Récupérer les entités sélectionnées
        selected_luminaires = layer_luminaires.selectedFeatures()
        selected_prises = layer_prises.selectedFeatures()

        if len(selected_luminaires) == 0 and len(selected_prises) == 0 :
            QMessageBox.warning(None, "Avertissement", "Aucun élément sélectionné !")
            return

        total_features = len(selected_luminaires) + len(selected_prises)

        # 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()

        increment = int(100 / total_features) if total_features else 100

        # Démarrer l'édition de la couche
        if not layer_luminaires.isEditable():
            layer_luminaires.startEditing()

        # Boucle pour traiter toutes les entités luminaires
        for feature in selected_luminaires:
            #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 'luminaire' not in existingData['nouveau'] :
                existingData['nouveau']['luminaire'] = {}

            existingData['nouveau']['luminaire'].update(data)

            # Modifier
            feature.setAttribute('data',  existingData)

            #Validation de la modification
            layer_luminaires.updateFeature(feature)

        # Démarrer l'édition de la couche
        if not layer_prises.isEditable():
            layer_prises.startEditing()

        # Boucle pour traiter toutes les entités luminaires
        for feature in selected_prises:
            #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)

            # Modifier
            feature.setAttribute('data',  existingData)

            #Validation de la modification
            layer_prises.updateFeature(feature)

        # 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}")


def formulaire(iface):
    try:
        # Créer une instance de QDialog
        dialog = QDialog()
        
        # Charger le fichier .ui dans le QDialog
        loadUi(ui_path, dialog)

        # Charger les couches nécessaires
        layer_etablissements = QgsProject.instance().mapLayersByName("Etablissements")[0]
        layer_armoires = QgsProject.instance().mapLayersByName("Armoires")[0]
        layer_departs = QgsProject.instance().mapLayersByName("Départs")[0]

        if not layer_etablissements or not layer_armoires or not layer_departs:
            QMessageBox.critical(None, "Erreur", "Les couches nécessaires ne sont pas disponibles.")
            return

        # Définition des variables
        items_code_proprietaire_armoire = {}
        items_code_armoire = {}
        items_code_depart = {}
        data = {}

        # Préparer l'autocomplétion pour le champ `nouveau_code_proprietaire_armoire`
        items_code_proprietaire_armoire.clear()  # Vider armoires pour chaque mise à jour
        for feature in layer_etablissements.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_proprietaire_armoire[display_text] = code

        completer_code_proprietaire_armoire = QCompleter(list(items_code_proprietaire_armoire.keys()))
        completer_code_proprietaire_armoire.setCaseSensitivity(Qt.CaseInsensitive)
        completer_code_proprietaire_armoire.setFilterMode(Qt.MatchContains)

        # Fonction pour gérer la sélection dans le champ
        def on_code_proprietaire_armoire_selected(display_text):
            # Récupération de la valeur du code
            data['code_proprietaire_armoire'] = items_code_proprietaire_armoire.get(dialog.nouveau_code_proprietaire_armoire.text())
            update_armoire_completer()
            # Donne le focus sur le champ
            dialog.nouveau_code_armoire.setFocus()

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_code_proprietaire_armoire.activated.connect(on_code_proprietaire_armoire_selected)

        # On lie le completer au bon champ du formulaire
        dialog.nouveau_code_proprietaire_armoire.setCompleter(completer_code_proprietaire_armoire)

        # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_proprietaire_armoire`
        dialog.nouveau_code_proprietaire_armoire.textChanged.connect(lambda: (
            dialog.nouveau_code_armoire.clear(),  # Vider le champ `nouveau_code_armoire`
            data.pop('code_armoire', None)  # Supprimer la clé 'code_armoire' de `data`
        ))

        # Préparer l'autocomplétion pour le champ `nouveau_code_armoire`
        def update_armoire_completer():
            items_code_armoire.clear()  # Vider le tableau pour chaque mise à jour
            for feature in layer_armoires.getFeatures():
                if feature["code_proprietaire"] == data['code_proprietaire_armoire'] :
                    code = feature["code"]
                    libelle = feature["libelle"]
                    display_text = f"{code} - {libelle}" if libelle else code
                    items_code_armoire[display_text] = code

            completer_code_armoire = QCompleter(list(items_code_armoire.keys()))
            completer_code_armoire.setCaseSensitivity(Qt.CaseInsensitive)
            completer_code_armoire.setFilterMode(Qt.MatchContains)

            # Fonction pour gérer la sélection dans le champ
            def on_code_armoire_selected(display_text):
                # Récupération de la valeur du code
                data['code_armoire'] = items_code_armoire.get(dialog.nouveau_code_armoire.text())
                update_depart_completer()
                # Donne le focus sur le champ
                dialog.nouveau_code_depart.setFocus()

            # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
            completer_code_armoire.activated.connect(on_code_armoire_selected)

            # On lie le completer au bon champ du formulaire
            dialog.nouveau_code_armoire.setCompleter(completer_code_armoire)

            # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_armoire`
            dialog.nouveau_code_armoire.textChanged.connect(lambda: (
            dialog.nouveau_code_depart.clear(),  # Vider le champ `nouveau_code_depart`
            data.pop('code_depart', None)  # Supprimer la clé 'code_depart' de `data`
        ))

        # Préparer l'autocomplétion pour le champ `nouveau_code_depart`
        def update_depart_completer():
            items_code_depart.clear()  # Vider le tableau pour chaque mise à jour
            for feature in layer_departs.getFeatures():
                if feature["code_proprietaire_armoire"] == data['code_proprietaire_armoire'] and feature["code_armoire"] == data['code_armoire']:
                    code = feature["code"]
                    libelle = feature["libelle"]
                    display_text = f"{code} - {libelle}" if libelle else code
                    items_code_depart[display_text] = code

            # Ajouter un élément "vide"
            dialog.nouveau_code_depart.addItem("Sélectionnez un départ")  

            # Ajouter les éléments dans le ComboBox
            dialog.nouveau_code_depart.addItems(items_code_depart.keys())

            # Fonction pour gérer la sélection dans le champ
            def on_code_depart_selected(display_text):
                # Récupération de la valeur du code
                data['code_depart'] = items_code_depart.get(dialog.nouveau_code_depart.currentText())

            # Connecter l'événement de sélection au ComboBox
            dialog.nouveau_code_depart.currentIndexChanged.connect(on_code_depart_selected)

        # 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_armoire' not in data or data['code_armoire'] == '':
                    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir une armoire")
                    return

                # Vérifier si le code_départ est vide
                if 'code_depart' not in data or data['code_depart'] == '':
                    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir un départ")
                    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}")
