import tkinter as tk
from tkinter import messagebox
import threading
import socket
import json
import time

# Variable pour stocker l'adresse IP
server_ip = "192.168.1.111"  # Adresse IP par défaut

# Fonction pour envoyer la commande de démarrage ou d'arrêt de la chauffe
def toggle_heating_state(heating_button):
    
    try:
        global server_ip
        if server_ip is None:
            raise ValueError("L'adresse IP du serveur n'est pas définie.")
        
        port = 4623  # Port du serveur

        btcolor = heating_button.cget("bg")
        current_state = 0 if btcolor == "gray" else 0

        # Si la chauffe est active (vert), envoyer la commande "stop"
        if current_state == 1:
            # print("stop")
            command = "stop"
            heating_button.config(bg="gray", text="Chauffe inactive")
        # Si la chauffe est inactive (gris), envoyer la commande "start"
        else:
            # print("start")
            command = "start"
            heating_button.config(bg="green", text="Chauffe active")
        

        # Créer la commande à envoyer au serveur
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((server_ip, port))
            # Envoi de la commande
            s.sendall(command.encode('utf-8'))
            # print(f"Commande envoyée : {command}")

    except Exception as e:
        print(f"Erreur lors de l'envoi de la commande de chauffe : {e}")

# Fonction pour mettre à jour la couleur du bouton "Chauffe active"
def update_heating_button(heating_button, state):
    if state == "IDLE":
        heating_button.config(bg="gray", text="Chauffe inactive")
        return "inactive"
    elif state == "ERROR":
        heating_button.config(bg="red", text="Erreur de chauffe")
        return "error"
    else:
        heating_button.config(bg="green", text="Chauffe active")
        return "active"

# Fonction pour récupérer les données depuis la socket
def start_socket_listener(update_widgets):
    try:
        global server_ip
        if server_ip is None:
            raise ValueError("L'adresse IP du serveur n'est pas définie.")
        
        port = 4623         # Port du serveur

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((server_ip, port))
            while True:
                try:
                    # Envoi de la commande "get_json"
                    s.sendall(b"get_json")
                    # Lecture des données
                    data = s.recv(1024)  # Taille max des données reçues
                    if not data:
                        break
                    # Convertir les données en JSON
                    json_data = json.loads(data.decode('utf-8'))
                    # Mise à jour des widgets
                    update_widgets(json_data)
                except json.JSONDecodeError:
                    update_widgets({"error": "Données JSON non valides"})
                time.sleep(1)
    except Exception as e:
        update_widgets({"error": f"Erreur : {e}"})

# Fonction pour mettre à jour l'interface avec les données JSON
def update_interface_with_json(json_data, label, controller_buttons, enabled_buttons, temp_frame, heating_button):
    """
    Met à jour les widgets dans l'interface en fonction des données JSON reçues.
    """
    try:
        # Mise à jour des informations générales
        status = json_data.get("status", "Indisponible")
        state = json_data.get("state", "Indisponible")
        current_temp = json_data.get("t", "Indisponible")
        target_temp = json_data.get("target", "Indisponible")

        # Texte principal
        label.config(
            text=f"Status : {status}\n"
                 f"État : {state}\n"
                 f"Température actuelle : {current_temp} °C\n"
                 f"Température cible : {target_temp} °C"
        )

        # Mise à jour des boutons pour controllers
        controllers = json_data.get("controllers", [])
        for i, state in enumerate(controllers):
            color = "green" if state else "gray"
            controller_buttons[i].config(bg=color, text=f"Carte OK {i}")

        # Mise à jour des boutons pour enabled
        enabled = json_data.get("enabled", [])
        for i, state in enumerate(enabled):
            color = "green" if state else "gray"
            enabled_buttons[i].config(bg=color, text=f"Zone active {i}")

        # Mise à jour du tableau des températures
        temps = json_data.get("temps", [])
        display_temperatures(temps, temp_frame)

        # Mise à jour de la couleur du bouton "Chauffe active"
        heating_state = json_data.get("state", [])
        update_heating_button(heating_button, heating_state)

        # Retourner l'état de chauffe actuel
        return heating_state

    except Exception as e:
        label.config(text=f"Erreur d'analyse : {e}")
        return "error"

# Fonction pour quitter proprement
def on_close(root):
    if messagebox.askokcancel("Quitter", "Voulez-vous vraiment quitter ?"):
        root.destroy()

# Fonction pour afficher les températures dans un tableau
def display_temperatures(temps, temp_frame):
    for widget in temp_frame.winfo_children():
        widget.destroy()

    for i in range(0, len(temps), 4):
        row = tk.Frame(temp_frame)
        row.pack(pady=5)
        for j in range(4):
            if i + j < len(temps):
                temp_label = tk.Label(row, text=f"{temps[i + j]:.1f} °C", width=10)
                temp_label.pack(side="left", padx=5)

# Fonction pour ouvrir une fenêtre de modification de la température cible
def open_target_window():
    def update_target():
        # Récupérer la température entrée par l'utilisateur
        try:
            new_target = float(target_entry.get())
            # Envoyer la commande avec la nouvelle température
            command = f"set_target {new_target}"
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.connect((server_ip, 4623))
                s.sendall(command.encode('utf-8'))
            # Fermer la fenêtre après avoir envoyé la commande
            target_window.destroy()
        except ValueError:
            messagebox.showerror("Erreur", "Veuillez entrer une température valide.")

    # Création de la fenêtre pour changer la température cible
    target_window = tk.Toplevel()
    target_window.title("Modifier Température Cible")
    target_window.geometry("300x150")

    # Ajouter un champ de saisie pour la nouvelle température
    target_label = tk.Label(target_window, text="Nouvelle température cible :")
    target_label.pack(pady=10)

    target_entry = tk.Entry(target_window)
    target_entry.pack(pady=5)

    # Bouton pour valider la température
    confirm_button = tk.Button(target_window, text="Valider", command=update_target)
    confirm_button.pack(pady=10)

# Fonction pour activer ou désactiver une zone en envoyant une commande
def toggle_zone(zone_number, enabled_buttons):
    try:
        global server_ip
        if server_ip is None:
            raise ValueError("L'adresse IP du serveur n'est pas définie.")
        
        # Vérifier l'état actuel de la zone
        current_state = enabled_buttons[zone_number].cget("bg")
        new_state = 1 if current_state == "gray" else 0
        # Envoi de la commande "set_zone"
        command = f"set_zone {zone_number} {new_state}"
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((server_ip, 4623))
            s.sendall(command.encode('utf-8'))
        # Mettre à jour la couleur du bouton en fonction de l'état
        new_color = "green" if new_state == 1 else "gray"
        enabled_buttons[zone_number].config(bg=new_color, text=f"Zone active {zone_number}")
    except Exception as e:
        print(f"Erreur lors du changement de l'état de la zone {zone_number}: {e}")

# Fenêtre de configuration de l'adresse IP
def configure_ip():
    def submit_ip():
        global server_ip
        ip = ip_entry.get()
        try:
            # Vérification simple de l'adresse IP (vous pouvez ajouter une validation plus complète)
            socket.inet_aton(ip)
            server_ip = ip
            ip_window.destroy()
            create_app()  # Lancer l'application principale
        except socket.error:
            messagebox.showerror("Erreur", "Adresse IP invalide. Veuillez entrer une adresse IP valide.")

    ip_window = tk.Tk()
    ip_window.title("Configuration Adresse IP")
    ip_window.geometry("400x200")

    ip_label = tk.Label(ip_window, text="Entrez l'adresse IP du serveur :")
    ip_label.pack(pady=10)

    ip_entry = tk.Entry(ip_window)
    ip_entry.pack(pady=5)
    ip_entry.insert(0, server_ip)  # Remplir avec l'IP par défaut

    submit_button = tk.Button(ip_window, text="Valider", command=submit_ip)
    submit_button.pack(pady=20)

    ip_window.mainloop()

# Fonction principale pour créer l'interface
def create_app():
    # Créer la fenêtre principale
    root = tk.Tk()
    root.title("MHC Client")
    root.geometry("800x600")

    # Frame pour afficher les informations générales
    label = tk.Label(root, text="Données non reçues", font=("Arial", 12))
    label.pack(pady=20)

    # Créer des boutons pour les contrôleurs (Carte OK)
    controller_buttons = []
    controller_frame = tk.Frame(root)
    controller_frame.pack(pady=10)
    for i in range(2):
        button = tk.Button(controller_frame, text=f"Carte OK {i}", width=15, height=2)
        button.pack(side="left", padx=10)
        controller_buttons.append(button)

    # Créer des boutons pour les zones
    enabled_buttons = []
    enabled_frame = tk.Frame(root)
    enabled_frame.pack(pady=10)
    for i in range(4):
        button = tk.Button(enabled_frame, text=f"Zone active {i}", width=15, height=2, command=lambda i=i: toggle_zone(i, enabled_buttons))
        button.pack(side="left", padx=10)
        enabled_buttons.append(button)

    # Frame pour afficher les températures
    temp_frame = tk.Frame(root)
    temp_frame.pack(pady=20)

    # Bouton pour changer la température cible
    target_button = tk.Button(root, text="Changer la température cible", command=open_target_window)
    target_button.pack(pady=10)

    # Bouton pour gérer la chauffe
    heating_button = tk.Button(root, text="Chauffe inactive", bg="gray", width=15, height=2, command=lambda: toggle_heating_state(heating_button))
    heating_button.pack(pady=10)

    # Fonction de mise à jour des widgets après chaque lecture
    def update_widgets(json_data):
        heating_state = update_interface_with_json(json_data, label, controller_buttons, enabled_buttons, temp_frame, heating_button)
        return heating_state

    # Démarrer un thread pour écouter les données de la socket
    threading.Thread(target=start_socket_listener, args=(update_widgets,), daemon=True).start()

    # Fonction pour quitter proprement
    root.protocol("WM_DELETE_WINDOW", lambda: on_close(root))

    # Boucle principale de l'application
    root.mainloop()

if __name__ == "__main__":
    configure_ip()  # Ouvrir la fenêtre de configuration de l'IP avant de lancer l'application
