# -*- coding: utf-8 -*-
# gui/containers/_widget_style_service.py
"""Сервис локальной стилизации host-виджета без протекания style в subtree."""

from __future__ import annotations

import re
from typing import Optional, TYPE_CHECKING

from PySide6.QtCore import Qt

from gui.styles import APP_STYLES

if TYPE_CHECKING:
    from PySide6.QtWidgets import QWidget


_SELECTOR_BLOCK_RE = re.compile(r"([^{}]+)\{")


class WidgetStyleService:
    """Хранит explicit/inherited/effective style и применяет QSS только к host."""

    def __init__(self, host: QWidget) -> None:
        self._host = host
        self._theme = "dark" if host.palette().window().color().lightness() < 128 else "light"
        self._is_active = False
        self._explicit_style_key: Optional[str] = None
        self._explicit_active_style_key: Optional[str] = None
        self._inherited_style_key: Optional[str] = None
        self._last_style_role = ""
        self._last_stylesheet = ""
        self._last_styled_background = False

    @property
    def explicit_style_key(self) -> Optional[str]:
        return self._explicit_style_key

    @property
    def inherited_style_key(self) -> Optional[str]:
        return self._inherited_style_key

    @property
    def effective_style_key(self) -> Optional[str]:
        return self._explicit_style_key or self._inherited_style_key

    def has_explicit_style(self) -> bool:
        return self._explicit_style_key is not None

    def apply(
        self,
        style_key: Optional[str] = None,
        active_key: Optional[str] = None,
        is_active: Optional[bool] = None,
    ) -> bool:
        previous_effective = self.effective_style_key
        previous_render = self._current_render_key()
        if style_key is not None:
            self._explicit_style_key = style_key
            self._explicit_active_style_key = style_key if active_key is None else active_key
        elif active_key is not None:
            self._explicit_active_style_key = active_key
        if is_active is not None:
            self._is_active = bool(is_active)
        effective_changed = previous_effective != self.effective_style_key
        if effective_changed or previous_render != self._current_render_key():
            self._refresh_host()
        return effective_changed

    def set_inherited_style(self, style_key: Optional[str]) -> bool:
        previous_effective = self.effective_style_key
        previous_render = self._current_render_key()
        self._inherited_style_key = style_key
        effective_changed = previous_effective != self.effective_style_key
        if effective_changed or previous_render != self._current_render_key():
            self._refresh_host()
        return effective_changed

    def handle_theme_changed(self, theme: str) -> None:
        theme = (theme or "").strip().lower()
        if theme in {"dark", "light"} and theme != self._theme:
            self._theme = theme
            self._refresh_host()

    def _refresh_host(self) -> None:
        style_role = self.effective_style_key or ""
        render_key = self._current_render_key()
        resolved_key = self._resolve_theme_key(render_key)
        css = APP_STYLES.get(resolved_key, "") if resolved_key else ""
        stylesheet = self._scope_css_to_host(css, style_role) if css and style_role else ""
        styled_background = bool(css)
        if style_role != self._last_style_role:
            self._host.setProperty("style_role", style_role)
            self._last_style_role = style_role
        if stylesheet != self._last_stylesheet:
            self._host.setStyleSheet(stylesheet)
            self._last_stylesheet = stylesheet
        if styled_background != self._last_styled_background:
            self._host.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, styled_background)
            self._last_styled_background = styled_background

    def _resolve_theme_key(self, style_key: Optional[str]) -> Optional[str]:
        if not style_key:
            return None
        themed_key = f"{style_key}_{self._theme.upper()}"
        if themed_key in APP_STYLES:
            return themed_key
        return style_key if style_key in APP_STYLES else None

    def _current_render_key(self) -> Optional[str]:
        return self._explicit_active_style_key if self._is_active else self.effective_style_key

    def _scope_css_to_host(self, css: str, style_role: str) -> str:
        def replace(match: re.Match[str]) -> str:
            selectors = []
            for raw_selector in match.group(1).split(","):
                selector = raw_selector.strip()
                selectors.append(self._scope_selector(selector, style_role))
            return ", ".join(selectors) + " {"

        return _SELECTOR_BLOCK_RE.sub(replace, css)

    @staticmethod
    def _scope_selector(selector: str, style_role: str) -> str:
        if not selector or any(token in selector for token in (" ", ">", "+", "~")):
            return selector
        if 'style_role="' in selector:
            return selector
        pseudo_index = selector.find(":")
        base = selector if pseudo_index < 0 else selector[:pseudo_index]
        suffix = "" if pseudo_index < 0 else selector[pseudo_index:]
        return f'{base}[style_role="{style_role}"]{suffix}'
