# -*- coding: utf-8 -*-
# gui/containers/grid_container.py

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QGridLayout, QLayout, QWidget, QSizePolicy
from .percent_sized_widget import PercentSizedWidget
from .content_host import ContentHost


class GridContainer(PercentSizedWidget):
    """Сеточный контейнер с размерами в процентах от родителя."""

    def __init__(
        self,
        width_percent: int | float | None = None,
        height_percent: int | float | None = None,
        margin: int | tuple[int, int, int, int] = 0,
        content_margins: int | tuple[int, int, int, int] | None = None,
        spacing: int | None = None,
        horizontal_spacing: int = 0,
        vertical_spacing: int = 0,
        content_width_percent: int | None = None,
        content_height_percent: int | None = None,
        content_width: int | None = None,
        content_height: int | None = None,
        content_fit: bool = True,
        row_percentages: list[int | float] | None = None,
        col_percentages: list[int | float] | None = None,
        row_stretches: list[int] | None = None,
        col_stretches: list[int] | None = None,
        parent: QWidget | None = None,
        style: str | None = None,
        active_style: str | None = None,
        is_active: bool | None = None,
    ):
        super().__init__(width_percent, height_percent, parent)
        self._init_stylable()

        self._outer_layout = QGridLayout(self)
        self._outer_layout.setSpacing(0)

        applied_margins = content_margins if content_margins is not None else margin
        if isinstance(applied_margins, (list, tuple)) and len(applied_margins) == 4:
            self._outer_layout.setContentsMargins(*applied_margins)
        else:
            self._outer_layout.setContentsMargins(applied_margins, applied_margins, applied_margins, applied_margins)

        self._content_host = ContentHost(
            width_percent=content_width_percent,
            height_percent=content_height_percent,
            orientation="v",
            margin=0,
            spacing=0,
            parent=self,
        )
        self._content_host.set_content_fit(content_fit)

        if content_width is not None or content_height is not None:
            w = content_width if content_width is not None else self._content_host.sizeHint().width()
            h = content_height if content_height is not None else self._content_host.sizeHint().height()
            self._content_host.set_fixed_size(w, h)

        self._grid_widget = QWidget(self._content_host)
        self._layout = QGridLayout(self._grid_widget)

        if spacing is not None:
            self._layout.setHorizontalSpacing(spacing)
            self._layout.setVerticalSpacing(spacing)
        else:
            self._layout.setHorizontalSpacing(horizontal_spacing)
            self._layout.setVerticalSpacing(vertical_spacing)

        self._content_host.add_widget(self._grid_widget)

        self._outer_layout.addWidget(self._content_host, 0, 0)
        self._outer_layout.setRowStretch(0, 1)
        self._outer_layout.setColumnStretch(0, 1)

        self._row_percentages = []
        self._col_percentages = []

        if row_percentages is not None and col_percentages is not None:
            self.set_cell_percentages(row_percentages, col_percentages)

        if row_stretches is not None:
            self.set_row_stretches(row_stretches)
        if col_stretches is not None:
            self.set_col_stretches(col_stretches)

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


    def set_cell_percentages(self, row_percentages: list[int | float], col_percentages: list[int | float]):
        """Устанавливает процентное соотношение строк и столбцов."""
        if not row_percentages or not col_percentages:
            raise ValueError("Не указано процентное соотношение ячеек сетки")

        self._row_percentages = self.normalize_percentages(row_percentages)
        self._col_percentages = self.normalize_percentages(col_percentages)

        for row, percent in enumerate(self._row_percentages):
            self._layout.setRowStretch(row, int(percent))

        for col, percent in enumerate(self._col_percentages):
            self._layout.setColumnStretch(col, int(percent))

    def normalize_percentages(self, percentages: list[int | float]) -> list[float]:
        """Нормализует список процентов до суммы 100."""
        total = sum(percentages)
        if total == 0:
            return [100 / len(percentages)] * len(percentages)
        elif total != 100:
            return [p / total * 100 for p in percentages]
        return percentages.copy()

    def add_widget(self, widget: QWidget, row: int, col: int, 
                   row_span: int = 1, col_span: int = 1, 
                   alignment: str | None = None) -> None:
        
        if row + row_span - 1 >= len(self._row_percentages) or col + col_span - 1 >= len(self._col_percentages):
            raise IndexError(f"Ячейка ({row}, {col}) с span ({row_span}, {col_span}) вне диапазона сетки")

        self._layout.addWidget(widget, row, col, row_span, col_span)
        if isinstance(widget, PercentSizedWidget):
            widget.schedule_percent_update()

    def set_spacing(self, horizontal: int, vertical: int) -> None:
        """
        Устанавливает раздельные отступы между ячейками по горизонтали и вертикали.
        
        Args:
            horizontal: Отступ между колонками в пикселях.
            vertical: Отступ между строками в пикселях.
        """
        self._layout.setHorizontalSpacing(horizontal)
        self._layout.setVerticalSpacing(vertical)

    def get_layout(self) -> QLayout:
        return self._outer_layout

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

    def set_alignment(self, alignment: str) -> None:
        raise NotImplementedError("Qt alignment for containers is disabled; use content springs.")

    def set_column_minimum_width(self, col: int, width: int) -> None:
        """
        Устанавливает минимальную ширину колонки.
        
        Args:
            col: Индекс колонки (начиная с 0).
            width: Минимальная ширина в пикселях.
        """
        if col < 0:
            raise ValueError(f"Индекс колонки не может быть отрицательным: {col}")
        self._layout.setColumnMinimumWidth(col, width)

    def set_column_min_widths(self, widths: list[int]) -> None:
        for col, width in enumerate(widths):
            self.set_column_minimum_width(col, width)

    def set_row_stretches(self, stretches: list[int]) -> None:
        for row, stretch in enumerate(stretches):
            self._layout.setRowStretch(row, int(stretch))

    def set_col_stretches(self, stretches: list[int]) -> None:
        for col, stretch in enumerate(stretches):
            self._layout.setColumnStretch(col, int(stretch))

    def set_row_minimum_height(self, row: int, height: int) -> None:
        """
        Устанавливает минимальную высоту строки.
        
        Args:
            row: Индекс строки (начиная с 0).
            height: Минимальная высота в пикселях.
        """
        if row < 0:
            raise ValueError(f"Индекс строки не может быть отрицательным: {row}")
        self._layout.setRowMinimumHeight(row, height)

    def set_row_min_heights(self, heights: list[int]) -> None:
        for row, height in enumerate(heights):
            self.set_row_minimum_height(row, height)

    def get_available_size_for_content(self) -> tuple[int, int]:
        """Полезная внутренняя область (без учёта margin)."""
        margins = self._outer_layout.contentsMargins()
        w = self.width() - margins.left() - margins.right()
        h = self.height() - margins.top() - margins.bottom()
        return max(0, w), max(0, h)


# ============================================================================
# Примеры использования GridContainer
# ============================================================================
#
# Базовый пример: форма с двумя колонками (labels и inputs)
# ----------------------------------------------------------------------------
# grid = GridContainer(width_percent=100, margin=6, parent=parent_widget)
# grid.set_cell_percentages(row_percentages=[1, 1, 1], col_percentages=[40, 60])
# grid.set_spacing(horizontal=12, vertical=8)
# grid.set_column_minimum_width(0, 120)
#
# # Добавление виджетов (row, col)
# grid.add_widget(label1, 0, 0)
# grid.add_widget(input1, 0, 1)
# grid.add_widget(label2, 1, 0)
# grid.add_widget(input2, 1, 1)
# grid.add_widget(label3, 2, 0)
# grid.add_widget(input3, 2, 1)
#
# ============================================================================
# Пример: форма со stretch колонок (для пропорционального роста)
# ----------------------------------------------------------------------------
# grid = GridContainer(width_percent=100, height_percent=50)
# grid.set_cell_percentages(row_percentages=[1, 1], col_percentages=[1, 2])
# grid.set_spacing(horizontal=12, vertical=2)
# grid.set_column_minimum_width(0, 140)
#
# # Первая колонка растёт в 1x, вторая в 2x
# grid.add_widget(code_label, 0, 0)
# grid.add_widget(code_input, 0, 1)
# grid.add_widget(name_label, 1, 0)
# grid.add_widget(name_input, 1, 1)
#
# ============================================================================
# Сложная сетка с объединением ячеек (span)
# ----------------------------------------------------------------------------
# grid = GridContainer(width_percent=100, height_percent=100, spacing=10)
# grid.set_cell_percentages(
#     row_percentages=[20, 30, 50],
#     col_percentages=[25, 25, 25, 25]
# )
#
# # Виджет занимает 2 колонки (row_span=1, col_span=2)
# grid.add_widget(header_widget, 0, 0, row_span=1, col_span=4)
# grid.add_widget(sidebar_widget, 1, 0, row_span=2, col_span=1)
# grid.add_widget(content_widget, 1, 1, row_span=2, col_span=3)
#
# ============================================================================
# Важные замечания
# ----------------------------------------------------------------------------
# 1. set_cell_percentages ОБЯЗАТЕЛЕН перед add_widget, иначе IndexError
# 2. row_percentages и col_percentages автоматически нормализуются до 100%
#    Например: [1, 2, 1] → [25%, 50%, 25%]
# 3. spacing применяется ко всем ячейкам; set_spacing позволяет раздельный
#    horizontal/vertical spacing для более тонкой настройки
# 4. Minimum width/height гарантируют, что ячейка не сожмётся ниже лимита
#    даже при малом размере родителя
# 5. Для форм с парами label-input рекомендуется:
#    - col_percentages=[1, 2] (label уже, input шире)
#    - set_column_minimum_width(0, 120-140) для label
#    - horizontal_spacing=12, vertical_spacing=2-8
# ============================================================================




# ---------------------------------------------------------------------------
# Module workflow notes
# ---------------------------------------------------------------------------
#
# 1) Назначение модуля:
#    Сеточный контейнер с размерами в процентах от родителя. Обеспечивает
#    размещение виджетов в строках/столбцах с процентным распределением,
#    поддержкой span (объединения ячеек), выравнивания через spring-based
#    alignment и стилизации через APP_STYLES/тему.
#
# 2) Зависимости модуля:
#    Импорты: Qt, QGridLayout, QLayout, QWidget, QSizePolicy (PySide6)
#    Хост/базовый класс: StylableMixin + PercentSizedWidget (MRO)
#    Внутренние: ContentHost (content_host.py)
#    Внешние библиотеки: PySide6
#
# 3) Экспорт:
#    Класс GridContainer — сеточный контейнер.
#    Методы: set_cell_percentages(), normalize_percentages(), add_widget(),
#            set_spacing(), get_layout(), set_margins(), set_alignment(),
#            set_column_minimum_width(), set_column_min_widths(),
#            set_row_stretches(), set_col_stretches(),
#            set_row_minimum_height(), set_row_min_heights(),
#            get_available_size_for_content()
#
# 4) Состояние (поля):
#    _outer_layout   : QGridLayout — внешний layout (spring-based alignment).
#    _content_host   : ContentHost — промежуточный хост для внутренней сетки.
#    _grid_widget    : QWidget — виджет, содержащий внутренний QGridLayout.
#    _layout         : QGridLayout — внутренний layout для пользовательских ячеек.
#    _row_percentages: list[float] — нормализованные доли строк (до 100%).
#    _col_percentages: list[float] — нормализованные доли столбцов (до 100%).
#
# 5) Последовательность действий и вызовов:
#    __init__(params) -> super().__init__(w%, h%, parent)
#      -> _init_stylable() -> создание _outer_layout (QGridLayout)
#      -> создание ContentHost -> создание _grid_widget + _layout (QGridLayout)
#      -> _content_host.add_widget(_grid_widget)
#      -> set_cell_percentages() если row/col_percentages заданы
#      -> set_row_stretches() / set_col_stretches() если заданы
#      -> _apply_style() если style/active_style/is_active заданы
#    add_widget(widget, row, col, ...) -> проверка bounds -> _layout.addWidget()
#    set_cell_percentages(rows, cols) -> normalize -> setRowStretch/setColumnStretch
#
# 6) Побочные эффекты:
#    Мутирует stretch-значения QGridLayout при set_cell_percentages/stretches.
#    _apply_style() устанавливает stylesheet на self.
#    set_alignment() бросает NotImplementedError — запрещён.
#
# 7) Границы ответственности:
#    НЕ размещает виджеты автоматически — требует явного add_widget(row, col).
#    НЕ поддерживает alignment.
#    НЕ управляет auto_add_children (нет флага _auto_add_children).
#
# 8) Обработка ошибок:
#    set_cell_percentages: ValueError при пустых row/col_percentages.
#    add_widget: IndexError при выходе за пределы сетки.
#    set_column_minimum_width / set_row_minimum_height: ValueError при index < 0.
#    _parse_alignment_springs: удалён, alignment запрещён.
#
# 9) Инварианты и контракты:
#    - set_cell_percentages ОБЯЗАТЕЛЕН до add_widget, иначе IndexError.
#    - row/col_percentages нормализуются до суммы 100%.
#    - content_margins и margin — не одно и то же: content_margins приоритетнее.
#
# 10) Правило сопровождения:
#     Не менять двухуровневую компоновку (outer_layout → content_host → grid).
#     Не добавлять alignment в конструктор — запрещено правилами.
#     Примеры использования — в блоке комментариев внизу файла.
