"""
Reactive translation widgets for the LF-MRI GUI.

Each widget registers itself with i18n as a listener and automatically
re-translates when the language changes — no manual retranslate_ui needed.

Usage
-----
    from src.gui.tr_widgets import TrLabel, TrPushButton, TrGroupBox
    from src.gui.tr_widgets import bind_tab_text, bind_table_headers

    # Instead of:
    lbl = QLabel(i18n.tr("my_key"))          # + retranslate_ui: lbl.setText(i18n.tr(...))

    # Write:
    lbl = TrLabel("my_key")                  # auto-updates on language change

    # QTabWidget tab texts:
    bind_tab_text(tab_widget, idx=0, key="tab_main")

    # QTableWidget column headers:
    bind_table_headers(table, ["col_step", "col_status", "col_result"])
"""
from __future__ import annotations

from PySide6.QtWidgets import (
    QGroupBox, QLabel, QPushButton, QTabWidget, QTableWidget,
)

from src import i18n


# ---------------------------------------------------------------------------
# Base mixin
# ---------------------------------------------------------------------------

class _TrMixin:
    """
    Mixin that hooks a widget into i18n listeners.

    Subclass must call ``_tr_init(key)`` at the end of its ``__init__``,
    and implement ``_on_lang_changed()``.
    """

    def _tr_init(self, key: str) -> None:
        self._tr_key = key
        i18n.add_listener(self._on_lang_changed)
        # QWidget.destroyed is a C++ signal — safe to connect in Python
        self.destroyed.connect(self._tr_cleanup)  # type: ignore[attr-defined]

    def _tr_cleanup(self) -> None:
        i18n.remove_listener(self._on_lang_changed)

    def _on_lang_changed(self) -> None:  # pragma: no cover
        raise NotImplementedError


# ---------------------------------------------------------------------------
# Concrete reactive widgets
# ---------------------------------------------------------------------------

class TrLabel(QLabel, _TrMixin):
    """QLabel whose text re-translates automatically on language change."""

    def __init__(self, key: str, parent=None) -> None:
        super().__init__(i18n.tr(key), parent)
        self._tr_init(key)

    def _on_lang_changed(self) -> None:
        self.setText(i18n.tr(self._tr_key))


class TrPushButton(QPushButton, _TrMixin):
    """QPushButton whose text re-translates automatically on language change."""

    def __init__(self, key: str, parent=None) -> None:
        super().__init__(i18n.tr(key), parent)
        self._tr_init(key)

    def _on_lang_changed(self) -> None:
        self.setText(i18n.tr(self._tr_key))


class TrGroupBox(QGroupBox, _TrMixin):
    """QGroupBox whose title re-translates automatically on language change."""

    def __init__(self, key: str, parent=None) -> None:
        super().__init__(i18n.tr(key), parent)
        self._tr_init(key)

    def _on_lang_changed(self) -> None:
        self.setTitle(i18n.tr(self._tr_key))


# ---------------------------------------------------------------------------
# Helpers for non-widget items (tab texts, table headers)
# ---------------------------------------------------------------------------

def bind_tab_text(tab_widget: QTabWidget, idx: int, key: str) -> None:
    """
    Keep ``tab_widget.tabText(idx)`` translated at all times.

    Call once after the tab is added::

        self._tabs.addTab(w, i18n.tr("tab_main"))
        bind_tab_text(self._tabs, 0, "tab_main")
    """
    def _update() -> None:
        tab_widget.setTabText(idx, i18n.tr(key))

    i18n.add_listener(_update)
    tab_widget.destroyed.connect(lambda: i18n.remove_listener(_update))


def bind_table_headers(table: QTableWidget, keys: list[str]) -> None:
    """
    Keep horizontal header labels of *table* translated at all times::

        bind_table_headers(self._steps_table, ["col_step", "col_status", "col_result"])
    """
    def _update() -> None:
        table.setHorizontalHeaderLabels([i18n.tr(k) for k in keys])

    i18n.add_listener(_update)
    table.destroyed.connect(lambda: i18n.remove_listener(_update))
