# -*- coding: utf-8 -*-
# gui/components/combo_box.py
"""Обёртка над QComboBox с централизованными стилями."""

from PySide6.QtWidgets import QComboBox, QSizePolicy
from PySide6.QtCore import Slot

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


class ComboBox(SContainer):
    """Кастомный QComboBox с темизацией и стилями APP_STYLES."""

    def __init__(
        self,
        width_percent: int | None = None,
        height_percent: int | None = None,
        margin: int | tuple[int, int, int, int] = 0,
        style: str = "FORM_WIDGET",
        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._combo = QComboBox()
        self._combo.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        super().add_widget(self._combo)

        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._combo.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._combo.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_items(self, items: list[str]) -> None:
        """Заменить список элементов."""
        self._combo.clear()
        self._combo.addItems(items)

    def set_editable(self, editable: bool) -> None:
        self._combo.setEditable(editable)

    def set_enabled(self, enabled: bool) -> None:
        """Управление доступностью."""
        self._combo.setEnabled(enabled)
        super().setEnabled(enabled)

    def set_min_width(self, width: int) -> None:
        """Минимальная ширина."""
        self._combo.setMinimumWidth(width)
        super().setMinimumWidth(width)

    def set_min_height(self, height: int) -> None:
        """Минимальная высота."""
        self._combo.setMinimumHeight(height)
        super().setMinimumHeight(height)

    def set_max_width(self, width: int) -> None:
        """Максимальная ширина."""
        self._combo.setMaximumWidth(width)
        super().setMaximumWidth(width)

    def set_max_height(self, height: int) -> None:
        """Максимальная высота."""
        self._combo.setMaximumHeight(height)
        super().setMaximumHeight(height)

    def set_fixed_size(self, width: int, height: int) -> None:
        """Фиксированный размер."""
        self._combo.setMinimumSize(width, height)
        self._combo.setMaximumSize(width, height)
        super().setMinimumSize(width, height)
        super().setMaximumSize(width, height)

    def set_index(self, index: int) -> None:
        """Установить текущий индекс."""
        self._combo.setCurrentIndex(index)

    def set_current_text(self, text: str) -> None:
        self._combo.setCurrentText(text)

    def set_placeholder_text(self, text: str) -> None:
        """Установить текст-заполнитель (если поддерживается Qt)."""
        line_edit = self._combo.lineEdit()
        if line_edit is not None:
            line_edit.setPlaceholderText(text)
        if hasattr(self._combo, "setPlaceholderText"):
            self._combo.setPlaceholderText(text)

    def get_index(self) -> int:
        """Получить текущий индекс."""
        return self._combo.currentIndex()

    def get_current_text(self) -> str:
        return self._combo.currentText()

    def set_tooltip(self, text: str) -> None:
        """Подсказка."""
        self._combo.setToolTip(text)

    def set_size_policy(self, horizontal, vertical) -> None:
        """Политика размеров."""
        self._combo.setSizePolicy(horizontal, vertical)
        super().setSizePolicy(horizontal, vertical)

    @property
    def current_index_changed(self):
        return self._combo.currentIndexChanged

    @property
    def current_text_changed(self):
        return self._combo.currentTextChanged

    @property
    def text_edited(self):
        line_edit = self._combo.lineEdit()
        if line_edit is None:
            raise AttributeError("text_edited is unavailable for non-editable ComboBox")
        return line_edit.textEdited

    def set_item_enabled(self, index: int, enabled: bool) -> None:
        """Включить/выключить элемент списка по индексу."""
        model = self._combo.model()
        if model is None:
            return
        item = model.item(index) if hasattr(model, "item") else None
        if item is not None and hasattr(item, "setEnabled"):
            item.setEnabled(bool(enabled))

    def show_popup(self) -> None:
        self._combo.showPopup()

    def add_widget(self, widget, alignment=None):
        raise NotImplementedError("ComboBox can contain only one QComboBox")



# ---------------------------------------------------------------------------
# Module workflow notes
# ---------------------------------------------------------------------------
#
# 1) Назначение модуля:
#    Обёртка над QComboBox, встроенная в SContainer, с поддержкой
#    централизованных стилей APP_STYLES и автоматическим
#    переключением тем (dark/light) через theme_bus.
#
# 2) Зависимости модуля:
#    Импорты: QComboBox, QSizePolicy (PySide6.QtWidgets),
#             Slot (PySide6.QtCore),
#             APP_STYLES (gui.styles),
#             theme_bus (gui.theme_bus),
#             SContainer (gui.containers.s_container)
#    Хост-класс / базовый класс: SContainer
#    Внешние библиотеки: PySide6 (обязательна)
#
# 3) Экспорт:
#    Класс ComboBox — публичный виджет выпадающего списка.
#    Методы: style(), set_theme(), set_items(), set_index(), get_index(),
#            set_placeholder_text(), set_enabled(), set_item_enabled(),
#            set_min/max_width/height(), set_fixed_size(), set_tooltip(),
#            set_size_policy().
#    Свойство: current_index_changed — сигнал currentIndexChanged.
#
# 4) Состояние (поля):
#    _theme: str                 — текущая тема ("dark" | "light")
#    _is_active: bool            — признак активного состояния
#    _base_style_key: str        — базовый ключ стиля (по умолчанию "FORM_WIDGET")
#    _style_key_normal: str|None — явный ключ нормального стиля
#    _style_key_active: str|None — явный ключ активного стиля
#    _combo: QComboBox           — внутренний виджет
#
# 5) Последовательность действий и вызовов:
#    __init__(style="FORM_WIDGET", ...)
#      -> super().__init__(...)
#      -> QComboBox() -> setSizePolicy -> super().add_widget(_combo)
#      -> style() — первичное применение
#      -> theme_bus.theme_changed.connect(set_theme)
#    style(style_key?, active_key?, is_active?)
#      -> определяет ключ через комбинацию base_key + тема + active
#      -> _combo.setStyleSheet(APP_STYLES[key])
#    set_items(items)
#      -> _combo.clear() -> _combo.addItems(items)
#
# 6) Побочные эффекты:
#    - Устанавливает stylesheet на внутренний QComboBox.
#    - Подключается к theme_bus.theme_changed при создании.
#
# 7) Границы ответственности:
#    Модуль НЕ хранит бизнес-данные выбранного элемента.
#    НЕ валидирует содержимое списка.
#    add_widget() заблокирован — компонент запечатан.
#
# 8) Обработка ошибок:
#    add_widget() бросает NotImplementedError.
#    set_theme() молча игнорирует невалидные значения.
#    set_item_enabled() безопасно пропускает отсутствующий model/item.
#
# 9) Инварианты и контракты:
#    - Контейнер содержит ровно один QComboBox.
#    - _theme ∈ {"dark", "light"}.
#    - Стиль разрешается по цепочке: явный ключ → base_key + суффикс темы.
#
# 10) Правило сопровождения:
#     Новые стили — добавлять в APP_STYLES с суффиксами _DARK/_LIGHT/_DARK_ACTIVE/_LIGHT_ACTIVE.
#     Делегирующие методы дублировать на _combo и super().
