"""
Theme Loader - Parse and load theme files with TOML frontmatter.
"""

import re
import tomllib
from functools import lru_cache
from pathlib import Path

from loguru import logger

from .schema import (
    REQUIRED_RGB_VARIANTS,
    REQUIRED_VARIABLES,
    ThemeMetadata,
)

# Pattern to match TOML frontmatter in CSS comments
# Matches: /*--- ... ---*/
FRONTMATTER_PATTERN = re.compile(r"/\*---\s*(.*?)\s*---\*/", re.DOTALL)

# Pattern to extract theme ID from CSS selector
THEME_ID_PATTERN = re.compile(r'\[data-theme="([^"]+)"\]')


class ThemeLoader:
    """Loads and parses theme files from a directory."""

    def __init__(self, themes_dir: Path):
        """Initialize loader with themes directory path."""
        self.themes_dir = themes_dir
        self._cache: dict[str, ThemeMetadata] = {}

    def parse_frontmatter(self, css_content: str) -> dict:
        """Extract and parse TOML frontmatter from CSS file.

        Args:
            css_content: The CSS file content

        Returns:
            Parsed TOML as dictionary, or empty dict if no frontmatter
        """
        match = FRONTMATTER_PATTERN.search(css_content)
        if not match:
            return {}
        try:
            return tomllib.loads(match.group(1))
        except tomllib.TOMLDecodeError as e:
            logger.warning(f"Failed to parse theme frontmatter: {e}")
            return {}

    def extract_theme_id(self, css_content: str) -> str | None:
        """Extract theme ID from CSS selector.

        Args:
            css_content: The CSS file content

        Returns:
            Theme ID string or None if not found
        """
        match = THEME_ID_PATTERN.search(css_content)
        return match.group(1) if match else None

    def validate_css_variables(
        self, css_content: str, theme_id: str
    ) -> tuple[list[str], list[str]]:
        """Validate that all required CSS variables are defined.

        Args:
            css_content: The CSS file content
            theme_id: Theme identifier for logging

        Returns:
            Tuple of (missing_base_vars, missing_rgb_vars)
        """
        missing_base = [
            var for var in REQUIRED_VARIABLES if var not in css_content
        ]
        missing_rgb = [
            var for var in REQUIRED_RGB_VARIANTS if var not in css_content
        ]
        return missing_base, missing_rgb

    def load_theme(self, css_path: Path) -> ThemeMetadata | None:
        """Load a single theme from a CSS file.

        Args:
            css_path: Path to the CSS file

        Returns:
            ThemeMetadata object or None if loading failed
        """
        try:
            content = css_path.read_text(encoding="utf-8")
            meta = self.parse_frontmatter(content)

            # Get theme ID from frontmatter or extract from CSS
            theme_id = (
                meta.get("id")
                or self.extract_theme_id(content)
                or css_path.stem
            )

            # Determine group from parent directory name
            parent_name = css_path.parent.name
            default_group = (
                parent_name
                if parent_name in {"core", "nature", "dev", "research"}
                else "other"
            )

            # Auto-generate metadata if not provided
            if not meta:
                meta = {
                    "id": theme_id,
                    "label": theme_id.replace("-", " ").title(),
                    "icon": "fa-palette",
                    "group": default_group,
                }
                logger.debug(f"Auto-generated metadata for theme: {theme_id}")

            # Validate CSS variables
            missing_base, missing_rgb = self.validate_css_variables(
                content, theme_id
            )
            if missing_base:
                logger.warning(
                    f"Theme {theme_id} missing base variables: {missing_base}"
                )
            if missing_rgb:
                logger.debug(
                    f"Theme {theme_id} missing RGB variants: {missing_rgb}"
                )

            # Determine theme type (dark/light)
            theme_type = meta.get("type", "dark")
            if theme_type not in ("dark", "light"):
                theme_type = "dark"

            return ThemeMetadata(
                id=theme_id,
                label=meta.get(
                    "label",
                    meta.get("name", theme_id.replace("-", " ").title()),
                ),
                icon=meta.get("icon", "fa-palette"),
                group=meta.get("group", default_group),
                type=theme_type,
                description=meta.get("description", ""),
                author=meta.get("author", ""),
                css_path=css_path,
            )
        except Exception:
            logger.exception(f"Failed to load theme: {css_path}")
            return None

    def get_css_content(self, theme: ThemeMetadata) -> str:
        """Get CSS content for a theme, stripping frontmatter.

        Args:
            theme: ThemeMetadata object

        Returns:
            CSS content without frontmatter
        """
        if not theme.css_path or not theme.css_path.exists():
            return ""
        content = theme.css_path.read_text(encoding="utf-8")
        # Strip frontmatter
        return FRONTMATTER_PATTERN.sub("", content).strip()

    @lru_cache(maxsize=1)
    def load_all_themes(self) -> dict[str, ThemeMetadata]:
        """Load all themes from the themes directory.

        Scans subdirectories (core/, nature/, dev/, research/) for .css files.

        Returns:
            Dictionary mapping theme IDs to ThemeMetadata objects
        """
        themes: dict[str, ThemeMetadata] = {}

        # Add virtual "system" theme (no CSS file)
        themes["system"] = ThemeMetadata(
            id="system",
            label="System",
            icon="fa-desktop",
            group="system",
            type="dark",  # Resolves at runtime based on OS preference
            description="Follow system color scheme preference",
            css_path=None,
        )

        # Scan subdirectories for theme files
        subdirs = ["core", "nature", "dev", "research"]
        for subdir in subdirs:
            dir_path = self.themes_dir / subdir
            if dir_path.exists():
                for css_file in sorted(dir_path.glob("*.css")):
                    theme = self.load_theme(css_file)
                    if theme:
                        themes[theme.id] = theme

        # Also scan root themes directory for any loose theme files
        for css_file in sorted(self.themes_dir.glob("*.css")):
            theme = self.load_theme(css_file)
            if theme and theme.id not in themes:
                themes[theme.id] = theme

        logger.info(f"Loaded {len(themes)} themes from {self.themes_dir}")
        return themes

    def clear_cache(self) -> None:
        """Clear the theme cache (useful for development/hot-reload)."""
        self._cache.clear()
        self.load_all_themes.cache_clear()
