# -*- coding: utf-8 -*-
# gui/components/tab_widget.py

from typing import Any, List, Optional, Type

from PySide6.QtCore import Signal
from PySide6.QtGui import QResizeEvent, QShowEvent
from PySide6.QtWidgets import QWidget

from gui.containers.s_container import SContainer
from gui.containers.h_container import HContainer
from gui.containers.stack_container import StackContainer

from gui.components.tab_button import TabButton
from error_logger import log_exception


class TabWidget(SContainer):
    """
    Процентный TabWidget:
    - Верхняя панель вкладок (HContainer) заданной высоты в %
    - Контент (StackContainer + QStackedWidget) занимает оставшуюся высоту
    """

    currentChanged = Signal(int)

    def __init__(
        self,
        width_percent: Optional[int] = None,
        height_percent: Optional[int] = None,
        tab_bar_height_percent: int = 8,
        margin: int = 0,
        parent: Optional[QWidget] = None,
        content_fit: bool = True,
        style: Optional[str] = None,
        active_style: Optional[str] = None,
        is_active: Optional[bool] = None,
        button_cls: Type = TabButton,
        button_style_normal: Optional[str] = None,
        button_style_active: Optional[str] = None,
        button_width_percent: Optional[int] = None,
        button_height_percent: Optional[int] = None,
        button_margin: Optional[list[int]] = None,
        button_inner_margin: Optional[int] = None,
        tab_bar_content_fit: bool = True,
    ):
        super().__init__(
            width_percent=width_percent,
            height_percent=height_percent,
            orientation="v",
            margin=margin,
            content_fit=content_fit,
            parent=parent
        )

        if not (1 <= tab_bar_height_percent <= 99):
            raise ValueError("tab_bar_height_percent должен быть в диапазоне 1..99")

        self._tab_bar_height_percent = tab_bar_height_percent
        self._content_height_percent = 100 - tab_bar_height_percent

        # Верхняя панель вкладок
        self._tab_bar = HContainer(
            height_percent=self._tab_bar_height_percent,
            margin=0,
            content_fit=tab_bar_content_fit,
        )

        # Контентная часть
        self._content_container = StackContainer(
            width_percent=100,
            height_percent=self._content_height_percent,
            margin=0
        )

        # Добавляем в основной VContainer
        self.add_widget(self._tab_bar)
        self.add_widget(self._content_container)

        self._button_cls = button_cls
        self._button_style_normal = button_style_normal
        self._button_style_active = button_style_active
        self._button_width_percent = button_width_percent
        self._button_height_percent = button_height_percent
        self._button_margin = button_margin
        self._button_inner_margin = button_inner_margin
        self._buttons: List[Any] = []

        if style is not None or active_style is not None or is_active is not None:
            self.style(style_key=style, active_key=active_style, is_active=is_active)

    # -------------------- Публичный API --------------------

    def showEvent(self, event: QShowEvent) -> None:
        super().showEvent(event)
        self._recompute_tab_button_widths()

    def resizeEvent(self, event: QResizeEvent) -> None:
        super().resizeEvent(event)
        self._recompute_tab_button_widths()

    def style(
        self,
        style_key: Optional[str] = None,
        active_key: Optional[str] = None,
        is_active: Optional[bool] = None,
    ) -> None:
        """Короткий метод применения стиля для TabWidget."""
        super().style(style_key=style_key, active_key=active_key, is_active=is_active)

    def add_tab(self, widget: QWidget, title: str) -> int:
        """
        Добавляет вкладку и страницу.
        Возвращает индекс новой вкладки.
        """
        index = len(self._buttons)

        btn = self._button_cls(
            text=title,
            index=index,
            width_percent=self._button_width_percent,
            height_percent=self._button_height_percent or 100,
            margin=self._button_margin if self._button_margin is not None else 0,
            text_left_margin=self._button_inner_margin,
            style=self._button_style_normal,
            active_style=self._button_style_active,
        )

        btn.clicked.connect(lambda checked=False, i=index: self.set_current_index(i))

        self._tab_bar.add_widget(btn)
        self._content_container.add_widget(widget)

        self._buttons.append(btn)
        self._recompute_tab_button_widths()

        # Если это первая вкладка — активируем
        if index == 0:
            self.set_current_index(0)

        return index

    def set_current_index(self, index: int) -> None:
        if index < 0 or index >= self.count():
            return

        self._content_container.set_current_index(index)
        self._apply_active_style(index)
        self.currentChanged.emit(index)

    def current_index(self) -> int:
        return self._content_container.current_index()

    def widget(self, index: int) -> Optional[QWidget]:
        return self._content_container.widget(index)

    def count(self) -> int:
        return self._content_container.count()

    def remove_tab(self, index: int) -> None:
        if index < 0 or index >= self.count():
            return

        # 1) убрать кнопку
        btn = self._buttons.pop(index)
        btn.setParent(None)
        btn.deleteLater()

        # 2) убрать страницу
        w = self._content_container.widget(index)
        if w is not None:
            self._content_container.remove_widget(w)
        if w is not None:
            w.setParent(None)

        # 3) переиндексация кнопок и их callback
        for i, b in enumerate(self._buttons):
            b.index = i
            if hasattr(b, "set_property"):
                b.set_property("tab_index", i)
            try:
                b.clicked.disconnect()
            except Exception as e:
                log_exception(__name__, "remove_tab.disconnect", e)
            b.clicked.connect(lambda checked=False, ii=i: self.set_current_index(ii))

        self._recompute_tab_button_widths()

        # 4) корректировка текущей
        if self.count() > 0:
            self.set_current_index(min(index, self.count() - 1))

    def set_tab_text(self, index: int, text: str) -> None:
        if 0 <= index < len(self._buttons):
            self._buttons[index].set_text(text)

    def set_tab_enabled(self, index: int, enabled: bool) -> None:
        if 0 <= index < len(self._buttons):
            self._buttons[index].set_enabled(enabled)

    def add_tab_bar_spacer(self, stretch: int = 1) -> None:
        """Добавляет растягиваемый спейсер в панель вкладок (прижимает кнопки влево)."""
        self._tab_bar.add_stretch(stretch)

    # -------------------- Внутренние --------------------

    def _apply_active_style(self, active_index: int) -> None:
        for i, b in enumerate(self._buttons):
            if i == active_index:
                b.style(is_active=True)
            else:
                b.style(is_active=False)

    def _recompute_tab_button_widths(self) -> None:
        """
        Делит 100% ширины между кнопками вкладок.
        Важное: проценты целые, сумма строго 100.
        """
        n = len(self._buttons)
        if n == 0:
            return

        base = 100 // n
        rem = 100 % n

        for i, b in enumerate(self._buttons):
            if self._button_width_percent is not None:
                w = self._button_width_percent
            else:
                w = base + (1 if i < rem else 0)
            h = self._button_height_percent or 100
            # API PercentSizedWidget
            b.set_percent_sizes(width_percent=w, height_percent=h)

        # Чтобы компоновка пересчиталась сразу
        self._tab_bar.invalidate_layout()
        tab_bar_layout = self._tab_bar.get_layout()
        if tab_bar_layout is not None:
            tab_bar_layout.activate()
        self._tab_bar.updateGeometry()
        self.updateGeometry()





# ---------------------------------------------------------------------------
# Module workflow notes
# ---------------------------------------------------------------------------
#
# 1) Назначение модуля:
#    Процентный TabWidget с верхней панелью вкладок (HContainer)
#    заданной высоты в % и контентной частью (StackContainer),
#    занимающей оставшуюся высоту.
#
# 2) Зависимости модуля:
#    Импорты: Any, List, Optional, Type (typing),
#             Signal, Qt (PySide6.QtCore),
#             QResizeEvent, QShowEvent (PySide6.QtGui),
#             QWidget (PySide6.QtWidgets),
#             SContainer (gui.containers.s_container),
#             HContainer (gui.containers.h_container),
#             StackContainer (gui.containers.stack_container),
#             TabButton (gui.components.tab_button)
#    Хост-класс / базовый класс: SContainer (orientation="v")
#    Внешние библиотеки: PySide6 (обязательна)
#
# 3) Экспорт:
#    Класс TabWidget — контейнер с вкладками.
#    Сигнал: currentChanged(int).
#    Методы: add_tab(widget, title) -> index, set_current_index(int),
#            current_index(), widget(index), count(), remove_tab(index),
#            set_tab_text(), set_tab_enabled(), add_tab_bar_spacer(),
#            style().
#
# 4) Состояние (поля):
#    _tab_bar_height_percent: int   — высота панели вкладок в %
#    _content_height_percent: int   — высота контента (100 - tab_bar)
#    _tab_bar: HContainer           — горизонтальный контейнер кнопок
#    _content_container: StackContainer — стек страниц
#    _button_cls: Type              — класс кнопки (по умолчанию TabButton)
#    _button_style_normal: str|None — нормальный стиль кнопок
#    _button_style_active: str|None — активный стиль кнопок
#    _button_width/height_percent: int|None — размеры кнопок
#    _button_margin: list[int]|None — отступы кнопок
#    _button_inner_margin: int|None — внутренний отступ текста
#    _buttons: list[TabButton]      — список кнопок вкладок
#
# 5) Последовательность действий и вызовов:
#    __init__(tab_bar_height_percent, ...)
#      -> super().__init__(orientation="v")
#      -> HContainer(height_percent) — панель вкладок
#      -> StackContainer(height_percent) — стек контента
#      -> self.add_widget(_tab_bar) + self.add_widget(_content_container)
#    add_tab(widget, title)
#      -> TabButton(text, index, ...) -> clicked.connect(set_current_index)
#      -> _tab_bar.add_widget(btn) -> _content_container.add_widget(widget)
#      -> _recompute_tab_button_widths()
#      -> если первая вкладка → set_current_index(0)
#    set_current_index(index)
#      -> _content_container.set_current_index(index)
#      -> _apply_active_style(index) — is_active=True для текущей, False для остальных
#      -> currentChanged.emit(index)
#    remove_tab(index)
#      -> удалить кнопку, удалить страницу, переиндексировать оставшиеся
#      -> _recompute_tab_button_widths()
#    _recompute_tab_button_widths()
#      -> 100% / n кнопок → set_percent_sizes на каждую кнопку
#      -> invalidate_layout + activate + updateGeometry
#
# 6) Побочные эффекты:
#    - Модифицирует _tab_bar и _content_container при add/remove.
#    - Испускает currentChanged при смене вкладки.
#    - Пересчитывает ширину кнопок при showEvent/resizeEvent.
#
# 7) Границы ответственности:
#    Модуль управляет переключением страниц и визуальным состоянием
#    вкладок. НЕ определяет стили кнопок — делегирует TabButton.
#    НЕ создаёт содержимое страниц.
#
# 8) Обработка ошибок:
#    tab_bar_height_percent вне [1, 99] → ValueError.
#    set_current_index() / remove_tab() — проверка диапазона индекса.
#    disconnect() в remove_tab() обёрнут в try/except.
#
# 9) Инварианты и контракты:
#    - tab_bar_height_percent ∈ [1, 99].
#    - len(_buttons) == _content_container.count().
#    - Сумма width_percent всех кнопок == 100 (при автораскладке).
#    - Индексы кнопок совпадают с индексами страниц в StackContainer.
#
# 10) Правило сопровождения:
#     Для кастомизации кнопок — передать button_cls в конструктор.
#     Не манипулировать _tab_bar и _content_container напрямую —
#     использовать add_tab() / remove_tab().
