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-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-nouveau-noeud.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_luminaire = {}
items_code_usage_luminaire = {}
items_code_couleur = {}
items_code_type_source = {}
items_code_type_culot_source = {}
items_code_path_reference_source = {}
items_code_temperature_couleur = {}
items_code_forme_source = {}
items_code_reference_driver = {}
items_code_programme = {}

#Initialisation des Completer
completer_luminaire_code_marque = QCompleter()
completer_luminaire_code_reference_luminaire = QCompleter()
completer_luminaire_code_couleur = QCompleter()
completer_source_code_marque = QCompleter()
completer_source_code_path_reference_source = QCompleter()
completer_driver_code_programme = QCompleter()

# Charger les couches nécessaires
layer_marque = QgsProject.instance().mapLayersByName("Marques")[0]
layer_reference_luminaire = QgsProject.instance().mapLayersByName("Références luminaire")[0]
layer_usage_luminaire = QgsProject.instance().mapLayersByName("Usages luminaire")[0]
layer_couleur = QgsProject.instance().mapLayersByName("Couleurs")[0]
layer_type_source = QgsProject.instance().mapLayersByName("Types de source")[0]
layer_type_culot_source = QgsProject.instance().mapLayersByName("Types de culot")[0]
layer_reference_source = QgsProject.instance().mapLayersByName("Références source")[0]
layer_temperature_couleur = QgsProject.instance().mapLayersByName("Températures de couleur")[0]
layer_forme_source = QgsProject.instance().mapLayersByName("Formes de source")[0]
layer_reference_driver = QgsProject.instance().mapLayersByName("Références driver")[0]
layer_programme = QgsProject.instance().mapLayersByName("Programmes")[0]

def initData():
    global data
    data = {}
    data['luminaire'] = {}
    data['source'] = {}
    data['driver'] = {}


#######################################################################################################################################################################################################
#   Fonctions pour initialisaer les Completer
#######################################################################################################################################################################################################

"""Initialisation des marques de luminaire"""
def init_luminaire_code_marque(dialog, data):
    global completer_luminaire_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_luminaire_code_marque = QCompleter(list(items_code_marque.keys()))
    completer_luminaire_code_marque.setModel(model)
    completer_luminaire_code_marque.setCaseSensitivity(Qt.CaseInsensitive)
    completer_luminaire_code_marque.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_luminaire_code_marque.setCompleter(completer_luminaire_code_marque)


"""Initialisation des références de luminaire"""
def init_luminaire_code_reference_luminaire(dialog, data):
    global completer_luminaire_code_reference_luminaire

    # Vider le tableau pour chaque mise à jour
    items_code_reference_luminaire.clear()  

    # Récupération des données dans la couche
    for feature in layer_reference_luminaire.getFeatures():
        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_luminaire[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_reference_luminaire.keys()))

    # Alimentation du QCompleter pour l'autocomplétion
    completer_luminaire_code_reference_luminaire.setModel(model)
    completer_luminaire_code_reference_luminaire.setCaseSensitivity(Qt.CaseInsensitive)
    completer_luminaire_code_reference_luminaire.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_luminaire_code_reference_luminaire.setCompleter(completer_luminaire_code_reference_luminaire)


"""Initialisation des couleur de luminaire"""
def init_luminaire_code_couleur(dialog, data):
    global completer_luminaire_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_luminaire_code_couleur.setModel(model)
    completer_luminaire_code_couleur.setCaseSensitivity(Qt.CaseInsensitive)
    completer_luminaire_code_couleur.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_luminaire_code_couleur.setCompleter(completer_luminaire_code_couleur)

"""Initialisation des références de source"""
def init_source_code_path_reference_source(dialog, data):
    global completer_source_code_path_reference_source

    # Vider le tableau pour chaque mise à jour
    items_code_path_reference_source.clear()  

    for feature in layer_reference_source.getFeatures():
        if feature["code_type_source"] == data.get('code_type_source', '') :
            if feature["code_marque"] == data.get('code_marque', '') or data.get('code_marque', '') == '':
                code = feature["code_path"]
                libelle = feature["libelle_path"]
                libelle_marque = feature["libelle_marque"]
                display_text = f"{code}"
                items_code_path_reference_source[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_path_reference_source.keys()))

    # Alimentation du QCompleter pour l'autocomplétion
    completer_source_code_path_reference_source.setModel(model)
    completer_source_code_path_reference_source.setCaseSensitivity(Qt.CaseInsensitive)
    completer_source_code_path_reference_source.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_source_code_path_reference_source.setCompleter(completer_source_code_path_reference_source)


"""Initialisation des marques de source"""
def init_source_code_marque(dialog, data):
    global completer_source_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_source_code_marque = QCompleter(list(items_code_marque.keys()))
    completer_source_code_marque.setModel(model)
    completer_source_code_marque.setCaseSensitivity(Qt.CaseInsensitive)
    completer_source_code_marque.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_source_code_marque.setCompleter(completer_source_code_marque)


"""Initialisation des programmes de driver"""
def init_driver_code_programme(dialog, data):
    global completer_driver_code_programme

    for feature in layer_programme.getFeatures():
        code = feature["code"]
        libelle = feature["libelle"]
        display_text = f"{libelle}" if libelle else code
        items_code_programme[display_text] = code

    # Création ou mise à jour du modèle pour le QCompleter
    model = QStringListModel(list(items_code_programme.keys()))

    completer_driver_code_programme.setModel(model)
    completer_driver_code_programme.setCaseSensitivity(Qt.CaseInsensitive)
    completer_driver_code_programme.setFilterMode(Qt.MatchContains)

    # On lie le completer au bon champ du formulaire
    dialog.nouveau_driver_code_programme.setCompleter(completer_driver_code_programme)

#######################################################################################################################################################################################################
#   Fonctions pour les Update
#######################################################################################################################################################################################################

""" LES LUMINAIRES """

# Marque
def update_luminaire_code_marque():
    # Récupération de la valeur du code
    data['luminaire']['code_marque'] = items_code_marque.get(dialog.nouveau_luminaire_code_marque.text())
    # MAJ Champ enfant lié
    init_luminaire_code_reference_luminaire(dialog, data['luminaire'])
    # Donne le focus sur le champ enfant
    dialog.nouveau_luminaire_code_reference_luminaire.setFocus()

# Référence
def update_luminaire_code_reference_luminaire():
    # Récupération de la valeur du code
    data['luminaire']['code_reference_luminaire'] = items_code_reference_luminaire.get(dialog.nouveau_luminaire_code_reference_luminaire.text())

# Usage
def update_luminaire_code_usage_luminaire():
    # Récupération de la valeur du code
    data['luminaire']['code_usage_luminaire'] = items_code_usage_luminaire.get(dialog.nouveau_luminaire_code_usage_luminaire.currentText())

# Puissance
def update_luminaire_puissance():
    data['luminaire']['puissance'] = dialog.nouveau_luminaire_puissance.text()

# Flux
def update_luminaire_flux_lumineux():
    data['luminaire']['flux_lumineux'] = dialog.nouveau_luminaire_flux_lumineux.text()

# Nature vasque
def update_luminaire_nature_vasque(checked, param_name):
    if checked:
        data['luminaire']['nature_vasque'] = param_name

# Forme vasque
def update_luminaire_forme_vasque(checked, param_name):
    if checked:
        data['luminaire']['forme_vasque'] = param_name

# Nature couleur
def update_luminaire_nature_couleur(checked, param_name):
    if checked:
        data['luminaire']['nature_couleur'] = param_name
    # MAJ Champ enfant lié
    init_luminaire_code_couleur(dialog, data['luminaire'])
    # Donne le focus sur le champ enfant
    dialog.nouveau_luminaire_code_couleur.setFocus()
    # Nettoyage de la clé dans Data
    data['luminaire'].pop('code_couleur', None)           
    # Donne le focus sur le champ
    dialog.nouveau_luminaire_code_couleur.clear(),  # Vider le champ

# Code couleur
def update_luminaire_code_couleur():
    # Récupération de la valeur du code
    data['luminaire']['code_couleur'] = items_code_couleur.get(dialog.nouveau_luminaire_code_couleur.text())

# Vétusté
def update_luminaire_vetuste(checked, param_name):
    if checked:
        data['luminaire']['vetuste'] = param_name

# Support bois
def update_luminaire_support_bois(checked, param_name):
    if checked:
        data['luminaire']['support_bois'] = param_name


# Support vétuste
def update_luminaire_support_vetuste(checked, param_name):
    if checked:
        data['luminaire']['support_vetuste'] = param_name


""" LES SOURCES """

# Type
def update_source_code_type_source():
    # Récupération de la valeur du code
    data['source']['code_type_source'] = items_code_type_source.get(dialog.nouveau_source_code_type_source.currentText())
    data['source'].pop('code_marque', None)  # Supprimer la clé de `data`
    dialog.nouveau_source_code_marque.clear(),  # Vider le champ
    dialog.nouveau_source_code_path_reference_source.clear(),  # Vider le champ
    # MAJ Champ enfant lié
    init_source_code_path_reference_source(dialog, data['source'])

# Quantité
def update_source_quantite():
    data['source']['quantite'] = dialog.nouveau_source_quantite.text()

# Nb LED
def update_source_nb_led():
    data['source']['nb_led'] = dialog.nouveau_source_nb_led.text()

# Marque
def update_source_code_marque():
    # Récupération de la valeur du code
    data['source']['code_marque'] = items_code_marque.get(dialog.nouveau_source_code_marque.text())
    # MAJ Champ enfant lié
    init_source_code_path_reference_source(dialog, data['source'])
    # Donne le focus sur le champ
    dialog.nouveau_source_code_path_reference_source.setFocus()

# Référence
def update_source_code_path_reference_source():
    # Récupération de la valeur du code
    data['source']['code_path_reference_source'] = items_code_path_reference_source.get(dialog.nouveau_source_code_path_reference_source.text())

# Température de couleur
def update_source_code_temperature_couleur():
    # Récupération de la valeur du code
    data['source']['code_temperature_couleur'] = items_code_temperature_couleur.get(dialog.nouveau_source_code_temperature_couleur.currentText())

# Forme
def update_source_code_forme_source():
    # Récupération de la valeur du code
    data['source']['code_forme_source'] = items_code_forme_source.get(dialog.nouveau_source_code_forme_source.currentText())

# Culot
def update_source_code_type_culot_source():
    # Récupération de la valeur du code
    data['source']['code_type_culot_source'] = items_code_type_culot_source.get(dialog.nouveau_source_code_type_culot_source.currentText())

# Remplacement identique
def update_source_remplacement_identique(checked, param_name):
    if checked:
        data['source']['remplacement_identique'] = param_name


""" LES DRIVERS """

# Fonction pour gérer la sélection dans le champ
def update_driver_code_reference_pilote():
    # Récupération de la valeur du code
    data['driver']['code_reference_pilote'] = items_code_reference_driver.get(dialog.nouveau_driver_code_reference_pilote.currentText())
    
# Fonction pour gérer la sélection dans le champ
def update_driver_code_programme():
    # Récupération de la valeur du code
    data['driver']['code_programme'] = items_code_programme.get(dialog.nouveau_driver_code_programme.text())
    
def update_driver_reglage():
    data['driver']['reglage'] = dialog.nouveau_driver_reglage.text()



#######################################################################################################################################################################################################
#   Fonctions pour les Coller les Data
#######################################################################################################################################################################################################

""" LUMINAIRES """

def pasteDataLuminaire(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('luminaire', {}).get('code_marque', ''):
                dialog.nouveau_luminaire_code_marque.setText(display_text)
                init_luminaire_code_reference_luminaire(dialog, data.get('nouveau', {}).get('luminaire', {}))
                update_luminaire_code_marque()
                break

        # Référence
        for display_text, code in items_code_reference_luminaire.items():
            if code == data.get('nouveau', {}).get('luminaire', {}).get('code_reference_luminaire', ''):
                dialog.nouveau_luminaire_code_reference_luminaire.setText(display_text)
                update_luminaire_code_reference_luminaire()
                break

        # Usage
        for display_text, code in items_code_usage_luminaire.items():
            if code == data.get('nouveau', {}).get('luminaire', {}).get('code_usage_luminaire', ''):
                dialog.nouveau_luminaire_code_usage_luminaire.setCurrentText(display_text)
                update_luminaire_code_usage_luminaire()
                break

        # Puissance
        dialog.nouveau_luminaire_puissance.setText(data.get('nouveau', {}).get('luminaire', {}).get('puissance', ''))
        update_luminaire_puissance()

        # Flux Lumineux
        dialog.nouveau_luminaire_flux_lumineux.setText(data.get('nouveau', {}).get('luminaire', {}).get('flux_lumineux', ''))
        update_luminaire_flux_lumineux()


        # Nature de la couleur
        if (data.get('nouveau', {}).get('luminaire', {}).get('nature_couleur', '')) == "Ral":
            dialog.nouveau_luminaire_nature_couleur_ral.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('nature_couleur', '')) == "Akzo":
            dialog.nouveau_luminaire_nature_couleur_akzo.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('nature_couleur', '')) == "Sublimation":
            dialog.nouveau_luminaire_nature_couleur_sublimation.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('nature_couleur', '')) == "RAS":
            dialog.nouveau_luminaire_nature_couleur_ras.setChecked(True)

        # Couleur
        for display_text, code in items_code_couleur.items():
            if code == data.get('nouveau', {}).get('luminaire', {}).get('code_couleur', ''):
                dialog.nouveau_luminaire_code_couleur.setText(display_text)
                update_luminaire_code_couleur()
                break
                
        # Vétusté
        if (data.get('nouveau', {}).get('luminaire', {}).get('vetuste', '')) == "Oui":
            dialog.nouveau_luminaire_vetuste_oui.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('vetuste', '')) == "Non":
            dialog.nouveau_luminaire_vetuste_non.setChecked(True)

        # Support en bois ?
        if (data.get('nouveau', {}).get('luminaire', {}).get('support_bois', '')) == "Oui":
            dialog.nouveau_luminaire_support_bois_oui.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('support_bois', '')) == "Non":
            dialog.nouveau_luminaire_support_bois_non.setChecked(True)

        # Support vétuste
        if (data.get('nouveau', {}).get('luminaire', {}).get('support_vetuste', '')) == "Oui":
            dialog.nouveau_luminaire_support_vetuste_oui.setChecked(True)
        elif (data.get('nouveau', {}).get('luminaire', {}).get('support_vetuste', '')) == "Non":
            dialog.nouveau_luminaire_support_vetuste_non.setChecked(True)


    else:
        print("Propriété non trouvée, valeur par défaut utilisée.")


""" SOURCES """

def pasteDataSource(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)

        # Type
        for display_text, code in items_code_type_source.items():
            if code == data.get('nouveau', {}).get('source', {}).get('code_type_source', ''):
                dialog.nouveau_source_code_type_source.setCurrentText(display_text)
                update_source_code_type_source()
                break
        
        # Quantité
        dialog.nouveau_source_quantite.setText(data.get('nouveau', {}).get('source', {}).get('quantite', ''))
        update_source_quantite()
        
        # Nombre de LED
        dialog.nouveau_source_nb_led.setText(data.get('nouveau', {}).get('source', {}).get('nb_led', ''))
        update_source_nb_led()

        # Marque
        for display_text, code in items_code_marque.items():
            if code == data.get('nouveau', {}).get('source', {}).get('code_marque', ''):
                dialog.nouveau_source_code_marque.setText(display_text)
                update_source_code_marque()
                break

        #Référence
        dialog.nouveau_source_code_path_reference_source.setText(data.get('nouveau', {}).get('source', {}).get('code_path_reference_source', ''))
        update_source_code_path_reference_source()

        #Température de couleur
        for display_text, code in items_code_temperature_couleur.items():
            if code == data.get('nouveau', {}).get('source', {}).get('code_temperature_couleur', ''):
                dialog.nouveau_source_code_temperature_couleur.setCurrentText(display_text)
                update_source_code_temperature_couleur()
                break

        # Forme
        for display_text, code in items_code_forme_source.items():
            if code == data.get('nouveau', {}).get('source', {}).get('code_forme_source', ''):
                dialog.nouveau_source_code_forme_source.setCurrentText(display_text)
                update_source_code_forme_source()
                break

        # Type culot
        for display_text, code in items_code_type_culot_source.items():
            if code == data.get('nouveau', {}).get('source', {}).get('code_type_culot_source', ''):
                dialog.nouveau_source_code_type_culot_source.setCurrentText(display_text)
                update_source_code_type_culot_source()
                break
    else:
        print("Propriété non trouvée, valeur par défaut utilisée.")


""" DRIVERS """

def pasteDataDriver(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)

        # Référence Pilote
        for display_text, code in items_code_reference_driver.items():
            if code == data.get('nouveau', {}).get('driver', {}).get('code_reference_pilote', ''):
                dialog.nouveau_driver_code_reference_pilote.setCurrentText(display_text)
                update_driver_code_reference_pilote()
                break

        # Programme
        for display_text, code in items_code_programme.items():
            if code == data.get('nouveau', {}).get('driver', {}).get('code_programme', ''):
                dialog.nouveau_driver_code_programme.setText(display_text)
                update_driver_code_programme()
                break

        # Réglage
        dialog.nouveau_driver_reglage.setText(data.get('nouveau', {}).get('driver', {}).get('reglage', ''))
        update_driver_reglage()

    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 Luminaires")[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 'luminaire' not in existingData['nouveau'] :
                existingData['nouveau']['luminaire'] = {}                
            existingData['nouveau']['luminaire'].update(data['luminaire'])

            if 'source' not in existingData['nouveau'] :
                existingData['nouveau']['source'] = {}                
            existingData['nouveau']['source'].update(data['source'])
            

            if 'driver' not in existingData['nouveau'] :
                existingData['nouveau']['driver'] = {}                
            existingData['nouveau']['driver'].update(data['driver'])

            # 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 Luminaire
        dialog.findChild(QPushButton, "btn_paste_luminaire").setEnabled(True)
        dialog.findChild(QPushButton, "btn_paste_luminaire").clicked.connect(
            lambda: pasteDataLuminaire(dialog)
        )

        #Bouton pour coller les Datas Source
        dialog.findChild(QPushButton, "btn_paste_source").setEnabled(True)
        dialog.findChild(QPushButton, "btn_paste_source").clicked.connect(
            lambda: pasteDataSource(dialog)
        )

        #Bouton pour coller les Datas Driver
        dialog.findChild(QPushButton, "btn_paste_driver").setEnabled(True)
        dialog.findChild(QPushButton, "btn_paste_driver").clicked.connect(
            lambda: pasteDataDriver(dialog)
        )

        #Bouton pour tout coller les Datas
        dialog.findChild(QPushButton, "btn_paste_all").setEnabled(True)
        dialog.findChild(QPushButton, "btn_paste_all").clicked.connect(
            lambda: (
                pasteDataLuminaire(dialog),
                pasteDataSource(dialog),
                pasteDataDriver(dialog)
            )
        )

        """ MARQUE DES LUMINAIRE """

        init_luminaire_code_marque(dialog, data['luminaire'])

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_luminaire_code_marque.activated.connect(update_luminaire_code_marque)      

        # Ajouter un gestionnaire pour le changement de texte dans `nouveau_code_marque_luminaire`
        dialog.nouveau_luminaire_code_marque.textChanged.connect(lambda: (
            dialog.nouveau_luminaire_code_reference_luminaire.clear(),  # Vider le champ enfant
            data['luminaire'].pop('code_reference_luminaire', None)  # Supprimer la clé de `data`
        ))

        """ REFERENCE LUMINAIRE """

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_luminaire_code_reference_luminaire.activated.connect(update_luminaire_code_reference_luminaire)


        """ USAGE LUMINAIRE """

        # On compléte le champ luminaire_code_usage_luminaire
        for feature in layer_usage_luminaire.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_usage_luminaire[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_luminaire_code_usage_luminaire.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_luminaire_code_usage_luminaire.addItems(items_code_usage_luminaire.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_luminaire_code_usage_luminaire.currentIndexChanged.connect(update_luminaire_code_usage_luminaire)

        """ PUISSANCE LUMINAIRE """

        # Détection changement de valeur
        dialog.nouveau_luminaire_puissance.editingFinished.connect(update_luminaire_puissance)


        """ FLUX LUMINEUX """     

        # Détection changement de valeur
        dialog.nouveau_luminaire_flux_lumineux.editingFinished.connect(update_luminaire_flux_lumineux)


        """ NATURE COULEUR """

        # Détection changement de valeur
        dialog.nouveau_luminaire_nature_couleur_ral.toggled.connect(lambda checked: update_luminaire_nature_couleur(checked, "Ral"))
        dialog.nouveau_luminaire_nature_couleur_akzo.toggled.connect(lambda checked: update_luminaire_nature_couleur(checked, "Akzo"))
        dialog.nouveau_luminaire_nature_couleur_sublimation.toggled.connect(lambda checked: update_luminaire_nature_couleur(checked, "Sublimation"))
        dialog.nouveau_luminaire_nature_couleur_ras.toggled.connect(lambda checked: update_luminaire_nature_couleur(checked, "RAS"))


        """ CODE COULEUR """

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_luminaire_code_couleur.activated.connect(update_luminaire_code_couleur)


        """ VETUSTE """

        # Détection changement de valeur
        dialog.nouveau_luminaire_vetuste_oui.toggled.connect(lambda checked: update_luminaire_vetuste(checked, "Oui"))
        dialog.nouveau_luminaire_vetuste_non.toggled.connect(lambda checked: update_luminaire_vetuste(checked, "Non"))

        """ SUPPORT BOIS """

        # Détection changement de valeur
        dialog.nouveau_luminaire_support_bois_oui.toggled.connect(lambda checked: update_luminaire_support_bois(checked, "Oui"))
        dialog.nouveau_luminaire_support_bois_non.toggled.connect(lambda checked: update_luminaire_support_bois(checked, "Non"))


        """ SUPPORT VETUSTE """

        # Détection changement de valeur
        dialog.nouveau_luminaire_support_vetuste_oui.toggled.connect(lambda checked: update_luminaire_support_vetuste(checked, "Oui"))
        dialog.nouveau_luminaire_support_vetuste_non.toggled.connect(lambda checked: update_luminaire_support_vetuste(checked, "Non"))

        #######################################################################################################################################################################################################
        #   Champs pour les sources
        #######################################################################################################################################################################################################

        """ TYPE """

        # On compléte le champ source_code_type_source
        for feature in layer_type_source.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_type_source[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_source_code_type_source.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_source_code_type_source.addItems(items_code_type_source.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_source_code_type_source.currentIndexChanged.connect(update_source_code_type_source)


        """ QUANTITE SOURCE """

        # Détection changement de valeur
        dialog.nouveau_source_quantite.editingFinished.connect(update_source_quantite)


        """ NB LED """  

        # Détection changement de valeur
        dialog.nouveau_source_nb_led.editingFinished.connect(update_source_nb_led)

        """ MARQUE  """

        init_source_code_marque(dialog, data['source'])

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_source_code_marque.activated.connect(update_source_code_marque)

        # Ajouter un gestionnaire pour le changement de texte
        dialog.nouveau_source_code_marque.textChanged.connect(lambda: (
            dialog.nouveau_source_code_path_reference_source.clear(),  # Vider le champ
            data['source'].pop('code_path_reference_source', None)  # Supprimer la clé de `data`
        ))

        """ REFERENCE SOURCE """           

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_source_code_path_reference_source.activated.connect(update_source_code_path_reference_source)

        # On lie le completer au bon champ du formulaire
        dialog.nouveau_source_code_path_reference_source.setCompleter(completer_source_code_path_reference_source)

        """ TEMPERATURE DE COULEUR """

        # On compléte le champ source_code_temperature_couleur
        for feature in layer_temperature_couleur.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_temperature_couleur[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_source_code_temperature_couleur.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_source_code_temperature_couleur.addItems(items_code_temperature_couleur.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_source_code_temperature_couleur.currentIndexChanged.connect(update_source_code_temperature_couleur)

        """ TYPE DE CULOT SOURCE """

        # On compléte le champ source_code_forme_source
        for feature in layer_forme_source.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_forme_source[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_source_code_forme_source.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_source_code_forme_source.addItems(items_code_forme_source.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_source_code_forme_source.currentIndexChanged.connect(update_source_code_forme_source)

        """ TYPE DE CULOT SOURCE """

        # On compléte le champ source_code_type_culot_source
        for feature in layer_type_culot_source.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_type_culot_source[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_source_code_type_culot_source.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_source_code_type_culot_source.addItems(items_code_type_culot_source.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_source_code_type_culot_source.currentIndexChanged.connect(update_source_code_type_culot_source)

        """ REMPLACEMENT IDENTIQUE """

        # Détection changement de valeur
        dialog.nouveau_source_remplacement_identique_oui.toggled.connect(lambda checked: update_source_remplacement_identique(checked, "Oui"))
        dialog.nouveau_source_remplacement_identique_non.toggled.connect(lambda checked: update_source_remplacement_identique(checked, "Non"))


        #######################################################################################################################################################################################################
        #   Champs pour les Drivers
        #######################################################################################################################################################################################################

        """ REFERENCE DRIVER """

        # On compléte le champ source_code_reference_driver
        for feature in layer_reference_driver.getFeatures():
            code = feature["code"]
            libelle = feature["libelle"]
            display_text = f"{code} - {libelle}" if libelle else code
            items_code_reference_driver[display_text] = code

        # Ajouter un élément "vide"
        dialog.nouveau_driver_code_reference_pilote.addItem("Sélectionnez une valeur")  

        # Ajouter les éléments dans le ComboBox
        dialog.nouveau_driver_code_reference_pilote.addItems(items_code_reference_driver.keys())

        # Connecter l'événement de sélection au ComboBox
        dialog.nouveau_driver_code_reference_pilote.currentIndexChanged.connect(update_driver_code_reference_pilote)

        """ PROGRAMME """

        init_driver_code_programme(dialog, data['driver'])

        # Définition de la fonction qui sera exécuté quand un élément sera sélectionné
        completer_driver_code_programme.activated.connect(update_driver_code_programme)


        """ REGLAGE """

        # Détection changement de valeur
        dialog.nouveau_driver_reglage.editingFinished.connect(update_driver_reglage)


        """ 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_luminaire' not in data['luminaire'] or data['luminaire']['code_reference_luminaire'] == '':
                #    QMessageBox.warning(None, "Saisie incomplète", "Il faut définir une référence luminaire")
                #    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}")
