# -*- coding: utf-8 -*-
# gui/components/group_box.py
"""Обёртка над QGroupBox с контейнером SContainer."""

from __future__ import annotations

from PySide6.QtCore import Slot, Qt
from PySide6.QtWidgets import QGroupBox, QVBoxLayout, QWidget, QSizePolicy

from gui.containers.s_container import SContainer
from gui.styles import APP_STYLES
from gui.theme_bus import theme_bus


class GroupBox(SContainer):
    """QGroupBox с централизованным стилем и внутренним layout по умолчанию."""

    _ALIGN_MAP = {
        "top": Qt.AlignmentFlag.AlignTop,
        "bottom": Qt.AlignmentFlag.AlignBottom,
        "left": Qt.AlignmentFlag.AlignLeft,
        "right": Qt.AlignmentFlag.AlignRight,
        "hcenter": Qt.AlignmentFlag.AlignHCenter,
        "vcenter": Qt.AlignmentFlag.AlignVCenter,
        "center": Qt.AlignmentFlag.AlignCenter,
    }

    def __init__(
        self,
        title: str = "",
        width_percent: int | None = None,
        height_percent: int | None = None,
        margin: int | tuple[int, int, int, int] = 0,
        content_margins: int | tuple[int, int, int, int] = 10,
        spacing: int = 8,
        alignment=None,
        style: str = "GROUP_BOX",
        active_style: str | None = None,
        is_active: bool | None = None,
        content_fit: bool = True,
        parent=None,
    ):
        super().__init__(
            width_percent=width_percent,
            height_percent=height_percent,
            margin=margin,
            style=style,
            active_style=active_style,
            is_active=is_active,
            content_fit=content_fit,
            parent=parent,
        )

        self._theme = "dark"
        self._is_active = False
        self._base_style_key = style
        self._style_key_normal = None
        self._style_key_active = None

        self._group_box = QGroupBox(title)
        self._group_box.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum)
        self._group_layout = QVBoxLayout()
        if isinstance(content_margins, (list, tuple)) and len(content_margins) == 4:
            self._group_layout.setContentsMargins(*content_margins)
        else:
            self._group_layout.setContentsMargins(content_margins, content_margins, content_margins, content_margins)
        self._group_layout.setSpacing(spacing)
        if alignment is not None:
            self._group_layout.setAlignment(self._normalize_alignment(alignment))
        self._group_box.setLayout(self._group_layout)

        super().add_widget(self._group_box)

        if active_style is not None:
            self._style_key_normal = style
            self._style_key_active = active_style
        if is_active is not None:
            self._is_active = bool(is_active)

        self.style()
        theme_bus.theme_changed.connect(self.set_theme)

    def style(
        self,
        style_key: str | None = None,
        active_key: str | None = None,
        is_active: bool | None = None,
    ) -> None:
        """Короткий метод применения стиля. Можно задать ключи и активность явно."""
        if style_key is not None:
            self._base_style_key = style_key
            if active_key is not None:
                self._style_key_normal = style_key
                self._style_key_active = active_key
            else:
                self._style_key_normal = None
                self._style_key_active = None

        if is_active is not None:
            self._is_active = bool(is_active)

        if self._style_key_normal is not None:
            active_key = self._style_key_active or self._style_key_normal
            key = active_key if self._is_active else self._style_key_normal
            themed = f"{key}_{self._theme.upper()}"
            if themed in APP_STYLES:
                key = themed
            self._group_box.setStyleSheet(APP_STYLES.get(key, ""))
            return

        base_key = self._base_style_key
        key = base_key

        if self._theme == "light":
            if self._is_active and f"{base_key}_LIGHT_ACTIVE" in APP_STYLES:
                key = f"{base_key}_LIGHT_ACTIVE"
            elif f"{base_key}_LIGHT" in APP_STYLES:
                key = f"{base_key}_LIGHT"
        else:
            if self._is_active and f"{base_key}_DARK_ACTIVE" in APP_STYLES:
                key = f"{base_key}_DARK_ACTIVE"
            elif f"{base_key}_DARK" in APP_STYLES:
                key = f"{base_key}_DARK"

        self._group_box.setStyleSheet(APP_STYLES.get(key, ""))

    @Slot(str)
    def set_theme(self, theme: str) -> None:
        """Внешний слот: принимает 'dark' или 'light'."""
        theme = (theme or "").strip().lower()
        if theme not in ("dark", "light"):
            return
        if self._theme == theme:
            return
        self._theme = theme
        self.style()

    def set_title(self, title: str) -> None:
        self._group_box.setTitle(title)

    def get_title(self) -> str:
        return self._group_box.title()

    def add_widget(self, widget: QWidget) -> None:
        self._group_layout.addWidget(widget)

    def add_stretch(self, stretch: int = 1) -> None:
        self._group_layout.addStretch(stretch)

    def set_margins(self, margin: int | tuple[int, int, int, int]) -> None:
        if isinstance(margin, (list, tuple)) and len(margin) == 4:
            self._group_layout.setContentsMargins(*margin)
        else:
            self._group_layout.setContentsMargins(margin, margin, margin, margin)

    def set_spacing(self, spacing: int) -> None:
        self._group_layout.setSpacing(spacing)

    def _normalize_alignment(self, alignment: str | Qt.Alignment) -> Qt.Alignment:
        """Преобразует строковое значение alignment в Qt.Alignment."""
        if isinstance(alignment, str):
            key = alignment.strip().lower()
            mapped = self._ALIGN_MAP.get(key)
            if mapped is None:
                raise ValueError(f"Unknown alignment '{key}'. Allowed: {list(self._ALIGN_MAP.keys())}")
            return mapped
        return alignment

    def set_alignment(self, alignment: str | Qt.Alignment) -> None:
        """Устанавливает выравнивание layout (строка или Qt.Alignment)."""
        self._group_layout.setAlignment(self._normalize_alignment(alignment))


# ---------------------------------------------------------------------------
# Module workflow notes
# ---------------------------------------------------------------------------
#
# 1) Назначение модуля:
#    Обёртка над QGroupBox, встроенная в SContainer, с заголовком,
#    внутренним QVBoxLayout для дочерних виджетов и поддержкой стилей
#    APP_STYLES + theme_bus.
#
# 2) Зависимости модуля:
#    Импорты: Slot, Qt (PySide6.QtCore),
#             QGroupBox, QVBoxLayout, QWidget, QSizePolicy (PySide6.QtWidgets),
#             SContainer (gui.containers.s_container),
#             APP_STYLES (gui.styles),
#             theme_bus (gui.theme_bus)
#    Хост-класс / базовый класс: SContainer
#    Внешние библиотеки: PySide6 (обязательна)
#
# 3) Экспорт:
#    Класс GroupBox — публичный контейнерный виджет с заголовком.
#    Методы: style(), set_theme(), set_title(), get_title(),
#            add_widget(QWidget), add_stretch(), set_margins(),
#            set_spacing(), set_alignment().
#
# 4) Состояние (поля):
#    _theme: str                 — текущая тема
#    _is_active: bool            — признак активного состояния
#    _base_style_key: str        — базовый ключ стиля ("GROUP_BOX")
#    _style_key_normal: str|None — явный нормальный стиль
#    _style_key_active: str|None — явный активный стиль
#    _group_box: QGroupBox       — внутренний QGroupBox
#    _group_layout: QVBoxLayout  — layout внутри QGroupBox
#    _ALIGN_MAP: dict            — маппинг строковых выравниваний в Qt.Alignment
#
# 5) Последовательность действий и вызовов:
#    __init__(title, content_margins, spacing, alignment, ...)
#      -> super().__init__(...)
#      -> QGroupBox(title) -> QVBoxLayout -> setContentsMargins, setSpacing
#      -> setAlignment(если передано)
#      -> _group_box.setLayout(_group_layout)
#      -> super().add_widget(_group_box) — добавление QGroupBox в SContainer
#      -> style() -> theme_bus.theme_changed.connect(set_theme)
#    add_widget(widget) — ПЕРЕОПРЕДЕЛЁН:
#      -> _group_layout.addWidget(widget) (добавляет внутрь QGroupBox, не в SContainer)
#
# 6) Побочные эффекты:
#    - Устанавливает stylesheet на QGroupBox.
#    - Подключается к theme_bus.theme_changed.
#    - add_widget() изменяет _group_layout (не SContainer layout).
#
# 7) Границы ответственности:
#    Модуль — визуальная группировка. НЕ реализует вложенные стили
#    для дочерних элементов. НЕ ограничивает типы дочерних виджетов.
#
# 8) Обработка ошибок:
#    _normalize_alignment() бросает ValueError при невалидной строке
#    выравнивания.
#
# 9) Инварианты и контракты:
#    - _group_box всегда имеет QVBoxLayout.
#    - Допустимые строки выравнивания: top, bottom, left, right,
#      hcenter, vcenter, center.
#    - add_widget() GroupBox — НЕ запечатан, принимает любые QWidget.
#
# 10) Правило сопровождения:
#     Если нужна горизонтальная компоновка внутри GroupBox —
#     вкладывать HContainer в add_widget(), не менять _group_layout на QHBoxLayout.
