# components/uart/uart_logger_ui.py
# Minimal UART Logger UI (no commands/table) — connect and stream logs.

import config.config as config


from PyQt6.QtWidgets import (
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QPushButton,
    QComboBox,
    QSplitter,
    QLabel,
)

from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtCore import QObject, pyqtSignal

# project-local deps
from components.console.console_ui import console_widget
from components.console.console_registry import log_main_console
import components.items.elements as elements

from components.uart.uart_logic import UART_logic
from components.scheduler.coordinator import (
    uart_capture_active,
    uart_capture_remaining_ms,
)


class _SafeConsoleProxy(QObject):
    log_signal = pyqtSignal(str, str)  # level, message

    def __init__(self, console):
        super().__init__()
        self.log_signal.connect(console.log)

    def __call__(self, level, msg):
        self.log_signal.emit(level, msg)


class UartLoggerWidget(QWidget):
    """
    Super-lean UART logger:
      - Port + serial params
      - Connect / Disconnect
      - Auto-start continuous logger on connect
      - One console
      - Capture indicator (global coordinator)
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.uart_logic = UART_logic()
        self.comboboxes = {}
        self.connection_status = False

        # console + have uart_logic log into it
        self.console = console_widget()

        # IMPORTANT: keep a strong reference so it isn’t GC’d
        self._uart_console_proxy = _SafeConsoleProxy(self.console)
        self.uart_logic.set_logger(self._uart_console_proxy)

        self.init_ui()
        self._wire_signals()
        self._setup_capture_guard()
        self.disconnected_enable_status()

    # ---------------- UI ----------------
    def init_ui(self):
        # === Top Control Row ===
        top_controls = QWidget()
        top_controls_layout = QHBoxLayout(top_controls)
        top_controls_layout.setContentsMargins(0, 0, 0, 0)
        top_controls_layout.setSpacing(12)
        top_controls_layout.setAlignment(Qt.AlignmentFlag.AlignTop)

        # Port + refresh
        self.comboboxes["port"] = QComboBox()
        self.comboboxes["port"].addItems(self.uart_logic.get_channels())
        top_controls_layout.addWidget(
            elements.label_and_widget("Port", self.comboboxes["port"])
        )

        self.button_refresh = elements.create_icon_button(
            config.REFRESH_BUTTON_ICON_LINK, icon_size=30, border_size=4
        )
        top_controls_layout.addWidget(self.button_refresh)

        # Serial params
        self.comboboxes["baudrate"] = QComboBox()
        self.comboboxes["baudrate"].addItems(self.uart_logic.get_baud_rates())
        top_controls_layout.addWidget(
            elements.label_and_widget("Baudrate", self.comboboxes["baudrate"])
        )

        self.comboboxes["data_bits"] = QComboBox()
        self.comboboxes["data_bits"].addItems(self.uart_logic.get_data_bits())
        top_controls_layout.addWidget(
            elements.label_and_widget("Data Bits", self.comboboxes["data_bits"])
        )

        self.comboboxes["stop_bits"] = QComboBox()
        self.comboboxes["stop_bits"].addItems(self.uart_logic.get_stop_bits())
        top_controls_layout.addWidget(
            elements.label_and_widget("Stop Bits", self.comboboxes["stop_bits"])
        )

        self.comboboxes["parity"] = QComboBox()
        self.comboboxes["parity"].addItems(self.uart_logic.get_parity())
        top_controls_layout.addWidget(
            elements.label_and_widget("Parity", self.comboboxes["parity"])
        )

        # Connect / Disconnect
        self.button_connect = QPushButton("Connect")
        top_controls_layout.addWidget(
            elements.label_and_widget("", self.button_connect)
        )

        self.button_disconnect = QPushButton("Disconnect")
        top_controls_layout.addWidget(
            elements.label_and_widget("", self.button_disconnect)
        )

        # Capture status label
        self.label_capture = QLabel("Capture: idle")
        top_controls_layout.addWidget(
            elements.label_and_widget("Status", self.label_capture)
        )

        # === Console only ===
        console_stack_widget = QWidget()
        console_stack_layout = QVBoxLayout(console_stack_widget)
        console_stack_layout.setContentsMargins(0, 0, 0, 0)
        console_stack_layout.setSpacing(4)
        console_stack_layout.addWidget(self.console)

        # === Splitter (kept for consistency, only console pane) ===
        splitter = QSplitter(Qt.Orientation.Horizontal)
        splitter.addWidget(console_stack_widget)
        splitter.setStretchFactor(0, 1)

        # === Main Layout ===
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(4, 4, 4, 4)
        main_layout.setSpacing(6)
        main_layout.addWidget(top_controls)
        main_layout.addWidget(splitter, stretch=1)
        self.setLayout(main_layout)

    def _wire_signals(self):
        self.button_refresh.clicked.connect(self.refresh)
        self.button_connect.clicked.connect(self.connect)
        self.button_disconnect.clicked.connect(self.disconnect)

    # ---------- Capture guard: label updates ----------
    def _setup_capture_guard(self):
        self._guard_timer = QTimer(self)
        self._guard_timer.setInterval(50)  # 20 Hz
        self._guard_timer.timeout.connect(self._update_capture_label)
        self._guard_timer.start()

    def _update_capture_label(self):
        if uart_capture_active():
            rem = uart_capture_remaining_ms()
            self.label_capture.setText(f"Capture: listening… {rem} ms")
        else:
            self.label_capture.setText("Capture: idle")

    # ---- UI state toggles ----
    def disconnected_enable_status(self):
        for combo in self.comboboxes.values():
            if combo.property("inversedGray"):
                elements.set_enabled_state(False, combo, grayOut=True)
            else:
                elements.set_enabled_state(True, combo, grayOut=False)

        elements.set_enabled_state(False, self.button_disconnect, grayOut=True)
        elements.set_enabled_state(True, self.button_connect, grayOut=False)

    def connected_enable_status(self):
        for combo in self.comboboxes.values():
            if combo.property("inversedGray"):
                elements.set_enabled_state(True, combo, grayOut=False)
            else:
                elements.set_enabled_state(False, combo, grayOut=True)

        elements.set_enabled_state(True, self.button_disconnect, grayOut=False)
        elements.set_enabled_state(False, self.button_connect, grayOut=True)

    # ---- Actions ----
    def connect(self):
        log_main_console("info", "🔗 Connecting (logger)…")
        port = self.comboboxes["port"].currentText()
        baudrate = int(self.comboboxes["baudrate"].currentText())
        data_bits = int(self.comboboxes["data_bits"].currentText())
        stop_bits = float(self.comboboxes["stop_bits"].currentText())
        parity_label = self.comboboxes["parity"].currentText()  # "Even", "None", "Odd"
        parity_short = parity_label[0].upper()  # E/N/O for your uart_logic

        ok = self.uart_logic.connect(
            port=port,
            baudrate=baudrate,
            data_bits=data_bits,
            stop_bits=stop_bits,
            parity=parity_short,
        )
        if ok:
            # auto-start continuous logger (hex output)
            self.uart_logic.start_logger(hex_output=True)
            self.connected_enable_status()
            self.connection_status = True
        else:
            elements.flash_button(
                self.button_connect, flash_style="background-color: red;"
            )

    def disconnect(self):
        log_main_console("info", "🔌 Disconnecting (logger)…")
        if self.uart_logic.disconnect():
            self.disconnected_enable_status()
            self.connection_status = False
            self.refresh(silent=True)
            self.uart_logic.stop_logger()
        else:
            elements.flash_button(
                self.button_disconnect, flash_style="background-color: red;"
            )

    def refresh(self, silent: bool = False):
        log_main_console("info", "🔄 Refreshing ports…")
        self.comboboxes["port"].clear()
        ports = self.uart_logic.get_channels()
        if ports:
            self.comboboxes["port"].addItems(ports)
            if not silent:
                elements.flash_button(self.button_refresh)
            log_main_console("success", "✅ Ports refreshed.")
        else:
            elements.flash_button(
                self.button_refresh, flash_style="background-color: red;"
            )
            log_main_console("warning", "⚠️ No UART ports found.")

    # helpful for diagnostics
    def get_current_config(self):
        return {key: cb.currentText() for key, cb in self.comboboxes.items()}
