# target_simulator/gui/settings_window.py

"""
A Toplevel window for configuring connection settings (Serial or TFTP).
"""

import tkinter as tk
from tkinter import ttk, messagebox
from typing import Dict, Any

from target_simulator.core.serial_communicator import SerialCommunicator, SERIAL_PARAMS
from target_simulator.core.tftp_communicator import TFTPCommunicator
from target_simulator.utils.config_manager import ConfigManager


class SettingsWindow(tk.Toplevel):
    """A dialog window for connection settings."""

    def __init__(
        self, master, config_manager: ConfigManager, current_config: Dict[str, Any]
    ):
        super().__init__(master)
        self.master_view = master
        self.config_manager = config_manager

        self.title("Connection Settings")
        self.transient(master)
        self.grab_set()
        self.resizable(False, False)

        # --- Variables ---
        self.comm_type_var = tk.StringVar(value=current_config.get("type", "serial"))
        self.serial_config_vars = self._setup_serial_vars(
            current_config.get("serial", {})
        )
        self.tftp_config_vars = self._setup_tftp_vars(current_config.get("tftp", {}))

        # --- UI Creation ---
        main_frame = ttk.Frame(self, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        self._create_type_selector(main_frame)

        # --- Configuration Frames ---
        self.serial_frame = self._create_serial_frame(main_frame)
        self.tftp_frame = self._create_tftp_frame(main_frame)

        self._create_buttons(main_frame)

        # --- Initial State ---
        self._on_comm_type_change()

        self.protocol("WM_DELETE_WINDOW", self.destroy)
        self.wait_window(self)

    def _setup_serial_vars(self, config: Dict) -> Dict[str, tk.StringVar]:
        return {
            "port": tk.StringVar(value=config.get("port", "")),
            "baudrate": tk.StringVar(value=config.get("baudrate", "115200")),
            "bytesize": tk.StringVar(value=config.get("bytesize", "8")),
            "parity": tk.StringVar(value=config.get("parity", "N")),
            "stopbits": tk.StringVar(value=config.get("stopbits", "1")),
        }

    def _setup_tftp_vars(self, config: Dict) -> Dict[str, tk.StringVar]:
        return {
            "ip": tk.StringVar(value=config.get("ip", "127.0.0.1")),
            "port": tk.StringVar(value=config.get("port", "69")),
        }

    def _create_type_selector(self, parent):
        frame = ttk.LabelFrame(parent, text="Communication Type", padding=10)
        frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Radiobutton(
            frame,
            text="Serial",
            variable=self.comm_type_var,
            value="serial",
            command=self._on_comm_type_change,
        ).pack(side=tk.LEFT, padx=10)

        ttk.Radiobutton(
            frame,
            text="TFTP",
            variable=self.comm_type_var,
            value="tftp",
            command=self._on_comm_type_change,
        ).pack(side=tk.LEFT, padx=10)

    def _create_serial_frame(self, parent) -> ttk.Frame:
        frame = ttk.LabelFrame(parent, text="Serial Port Settings", padding=10)

        # Grid layout for alignment
        frame.columnconfigure(1, weight=1)

        # Port
        ttk.Label(frame, text="Port:").grid(row=0, column=0, sticky=tk.W, pady=2)
        port_combo = ttk.Combobox(
            frame, textvariable=self.serial_config_vars["port"], state="readonly"
        )
        port_combo.grid(row=0, column=1, sticky=tk.EW, padx=5, pady=2)
        self._populate_ports(port_combo)

        # Baudrate
        ttk.Label(frame, text="Baud Rate:").grid(row=1, column=0, sticky=tk.W, pady=2)
        baud_combo = ttk.Combobox(
            frame,
            textvariable=self.serial_config_vars["baudrate"],
            values=SERIAL_PARAMS["baudrates"],
            state="readonly",
        )
        baud_combo.grid(row=1, column=1, sticky=tk.EW, padx=5, pady=2)

        # Parity
        ttk.Label(frame, text="Parity:").grid(row=2, column=0, sticky=tk.W, pady=2)
        parity_combo = ttk.Combobox(
            frame,
            textvariable=self.serial_config_vars["parity"],
            values=list(SERIAL_PARAMS["parities"]),
            state="readonly",
        )
        parity_combo.grid(row=2, column=1, sticky=tk.EW, padx=5, pady=2)

        return frame

    def _create_tftp_frame(self, parent) -> ttk.Frame:
        frame = ttk.LabelFrame(parent, text="TFTP Server Settings", padding=10)
        frame.columnconfigure(1, weight=1)

        # IP Address
        ttk.Label(frame, text="Server IP:").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Entry(frame, textvariable=self.tftp_config_vars["ip"]).grid(
            row=0, column=1, sticky=tk.EW, padx=5, pady=2
        )

        # Port
        ttk.Label(frame, text="Server Port:").grid(row=1, column=0, sticky=tk.W, pady=2)
        ttk.Entry(frame, textvariable=self.tftp_config_vars["port"]).grid(
            row=1, column=1, sticky=tk.EW, padx=5, pady=2
        )

        return frame

    def _create_buttons(self, parent):
        frame = ttk.Frame(parent, padding=(0, 10, 0, 0))
        frame.pack(fill=tk.X)

        ttk.Button(
            frame, text="Test Connection", command=self._on_test_connection
        ).pack(side=tk.LEFT, padx=(0, 10))

        # Right-align Save and Cancel
        ttk.Button(frame, text="Cancel", command=self.destroy).pack(side=tk.RIGHT)
        ttk.Button(frame, text="Save", command=self._on_save).pack(
            side=tk.RIGHT, padx=5
        )

    def _on_comm_type_change(self):
        """Show/hide frames based on the selected communication type."""
        selected_type = self.comm_type_var.get()
        if selected_type == "serial":
            self.tftp_frame.pack_forget()
            self.serial_frame.pack(fill=tk.X, expand=True)
        elif selected_type == "tftp":
            self.serial_frame.pack_forget()
            self.tftp_frame.pack(fill=tk.X, expand=True)

    def _populate_ports(self, combobox: ttk.Combobox):
        """Fetches and displays available serial ports."""
        available_ports = SerialCommunicator.list_available_ports()
        if available_ports:
            combobox["values"] = available_ports
            if not self.serial_config_vars["port"].get():
                self.serial_config_vars["port"].set(available_ports[0])
        else:
            combobox["values"] = ["No ports found"]
            self.serial_config_vars["port"].set("No ports found")

    def _on_test_connection(self):
        """Tests the connection for the currently selected mode."""
        comm_type = self.comm_type_var.get()
        is_success = False
        config = {}

        if comm_type == "serial":
            config = {key: var.get() for key, var in self.serial_config_vars.items()}
            is_success = SerialCommunicator.test_connection(config)
        else:  # tftp
            config = {key: var.get() for key, var in self.tftp_config_vars.items()}
            is_success = TFTPCommunicator.test_connection(config)

        if is_success:
            messagebox.showinfo(
                "Success",
                f"Connection test successful for {comm_type.upper()}.",
                parent=self,
            )
        else:
            messagebox.showerror(
                "Failure",
                f"Failed to connect using {comm_type.upper()} settings.",
                parent=self,
            )

    def _on_save(self):
        """Saves the selected settings and closes the window."""
        comm_type = self.comm_type_var.get()
        # Recupera la configurazione corrente
        current = (
            self.master_view.connection_config
            if hasattr(self.master_view, "connection_config")
            else {}
        )
        serial_conf = current.get("serial", {})
        tftp_conf = current.get("tftp", {})

        if comm_type == "serial":
            serial_conf = {
                key: var.get() for key, var in self.serial_config_vars.items()
            }
        else:
            tftp_conf = {key: var.get() for key, var in self.tftp_config_vars.items()}

        full_config = {"type": comm_type, "serial": serial_conf, "tftp": tftp_conf}
        self.master_view.update_connection_settings(full_config)
        self.destroy()
