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-sortie-pilote-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-sortie-pilote-nouveau-noeud.ui"

def execution(iface, formulaire, data):
    try:
        # Couche des luminaires
        layer_luminaires = QgsProject.instance().mapLayersByName("Noeuds Luminaires")[0]

        # Couche des 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
        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

            existingData = feature['data']
            if 'sortie_pilote' not in existingData['nouveau'] :
                existingData['nouveau']['sortie_pilote'] = {}

            existingData['nouveau']['sortie_pilote'].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 'sortie_pilote' not in existingData['nouveau'] :
                existingData['nouveau']['sortie_pilote'] = {}

            existingData['nouveau']['sortie_pilote'].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_etablissement = QgsProject.instance().mapLayersByName("Etablissements")[0]
        layer_armoire = QgsProject.instance().mapLayersByName("Armoires")[0]
        layer_pilote = QgsProject.instance().mapLayersByName("Pilotes")[0]
        layer_sortie_pilote = QgsProject.instance().mapLayersByName("Sorties de pilotes")[0]

        if not layer_etablissement or not layer_armoire or not layer_pilote:
            QMessageBox.critical(None, "Erreur", "Les couches nécessaires ne sont pas disponibles.")
            return

        # Définition des variables
        items_code_etablissement = {}
        items_code_armoire = {}
        items_code_pilote = {}
        items_code_sortie_pilote = {}
        data = {}

        """ PROPRIETAIRE HOTE PILOTE """

        # 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_etablissement.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_etablissement[display_text] = code

        completer_code_proprietaire_hote = QCompleter(list(items_code_etablissement.keys()))
        completer_code_proprietaire_hote.setCaseSensitivity(Qt.CaseInsensitive)
        completer_code_proprietaire_hote.setFilterMode(Qt.MatchContains)

        # Fonction pour gérer la sélection dans le champ
        def update_code_proprietaire_hote(display_text):
            # Récupération de la valeur du code
            data['code_proprietaire_hote'] = items_code_etablissement.get(dialog.nouveau_code_proprietaire_hote.text())
            update_armoire_completer()
            # Donne le focus sur le champ
            dialog.nouveau_code_path_hote.setFocus()

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_code_proprietaire_hote.activated.connect(update_code_proprietaire_hote)

        # On lie le completer au bon champ du formulaire
        dialog.nouveau_code_proprietaire_hote.setCompleter(completer_code_proprietaire_hote)

        # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_proprietaire_armoire`
        dialog.nouveau_code_proprietaire_hote.textChanged.connect(lambda: (
            dialog.nouveau_code_path_hote.clear(),  # Vider le champ
            data.pop('code_path_hote', None)  # Supprimer la clé de `data`
        ))


        """ ARMOIRE HOTE """

        # 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
            items_code_pilote.clear()  # Vider le tableau pour chaque mise à jour
            items_code_sortie_pilote.clear()  # Vider le tableau pour chaque mise à jour
            for feature in layer_armoire.getFeatures():
                if feature["code_proprietaire"] == data['code_proprietaire_hote'] :
                    code = feature["code"]
                    libelle = feature["libelle"]
                    display_text = f"{code} - {libelle}" if libelle else code
                    items_code_armoire[display_text] = code

            completer_code_path_hote = QCompleter(list(items_code_armoire.keys()))
            completer_code_path_hote.setCaseSensitivity(Qt.CaseInsensitive)
            completer_code_path_hote.setFilterMode(Qt.MatchContains)

            # Fonction pour gérer la sélection dans le champ
            def update_code_path_hote(display_text):
                # Récupération de la valeur du code
                data['code_path_hote'] = data['code_proprietaire_hote'] + '>' + items_code_armoire.get(dialog.nouveau_code_path_hote.text())
                update_pilote_completer()
                # Donne le focus sur le champ
                dialog.nouveau_code_pilote.setFocus()

            # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
            completer_code_path_hote.activated.connect(update_code_path_hote)

            # On lie le completer au bon champ du formulaire
            dialog.nouveau_code_path_hote.setCompleter(completer_code_path_hote)

            # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_armoire`
            dialog.nouveau_code_path_hote.textChanged.connect(lambda: (
                dialog.nouveau_code_pilote.clear(),  # Vider le champ `nouveau_code_depart`
                data.pop('code_pilote', None)  # Supprimer la clé 'code_depart' de `data`
            ))

        """ PILOTE """

        # Préparer l'autocomplétion pour le champ `nouveau_code_depart`
        def update_pilote_completer():
            items_code_pilote.clear()  # Vider le tableau pour chaque mise à jour
            for feature in layer_pilote.getFeatures():
                if feature["path_hote"] == data['code_path_hote']:
                    code = feature["code"]
                    libelle = feature["libelle_reference_pilote"]
                    display_text = f"{code} - {libelle}" if libelle else code
                    items_code_pilote[display_text] = code

            # Ajouter un élément "vide"
            dialog.nouveau_code_pilote.addItem("Sélectionnez un pilote")  

            # Ajouter les éléments dans le ComboBox
            dialog.nouveau_code_pilote.addItems(items_code_pilote.keys())

            # Fonction pour gérer la sélection dans le champ
            def update_code_pilote(display_text):
                # Récupération de la valeur du code
                data['code_pilote'] = items_code_pilote.get(dialog.nouveau_code_pilote.currentText())
                update_sortie_pilote_completer()
                # Donne le focus sur le champ
                dialog.nouveau_code_sortie_pilote.setFocus()

            # Connecter l'événement de sélection au ComboBox
            dialog.nouveau_code_pilote.currentIndexChanged.connect(update_code_pilote)


        """ SORTIE """

        # Préparer l'autocomplétion pour le champ `nouveau_code_depart`
        def update_sortie_pilote_completer():
            items_code_sortie_pilote.clear()  # Vider le tableau pour chaque mise à jour
            for feature in layer_sortie_pilote.getFeatures():
                if feature["path_hote_pilote"] == data['code_path_hote'] and feature["code_pilote"] == data['code_pilote'] :
                    code = feature["code"]
                    libelle = feature["libelle_last_programme"]
                    display_text = f"{code} - {libelle}" if libelle else code
                    items_code_sortie_pilote[display_text] = code

            # Ajouter un élément "vide"
            dialog.nouveau_code_sortie_pilote.addItem("Sélectionnez une sortie")  

            # Ajouter les éléments dans le ComboBox
            dialog.nouveau_code_sortie_pilote.addItems(items_code_sortie_pilote.keys())

            # Fonction pour gérer la sélection dans le champ
            def update_code_sortie_pilote(display_text):
                # Récupération de la valeur du code
                data['code_sortie_pilote'] = items_code_sortie_pilote.get(dialog.nouveau_code_sortie_pilote.currentText())

            # Connecter l'événement de sélection au ComboBox
            dialog.nouveau_code_sortie_pilote.currentIndexChanged.connect(update_code_sortie_pilote)

        # 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_proprietaire_hote' not in data or data['code_proprietaire_hote'] == '':
                    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir un propriétaire de pilote")
                    return

                # Vérifier si le code_départ est vide
                if 'code_pilote' not in data or data['code_pilote'] == '':
                    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir un pilote")
                    return

                # Vérifier si le code_départ est vide
                if 'code_sortie_pilote' not in data or data['code_sortie_pilote'] == '':
                    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir une sortie de pilote")
                    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}")
