"""
Theme System - Modular theme management with individual theme files.

This module provides a centralized theme registry that:
- Auto-discovers themes from CSS files with TOML frontmatter
- Generates combined CSS for browser consumption
- Provides theme metadata for UI dropdowns
- Integrates with Flask templates via Jinja2 globals

Usage:
    from local_deep_research.web.themes import theme_registry

    # Get all theme IDs
    themes = theme_registry.get_theme_ids()

    # Get theme metadata for JavaScript
    metadata_json = theme_registry.get_metadata_json()

    # Generate combined CSS
    css = theme_registry.get_combined_css()
"""

import json
from pathlib import Path

from loguru import logger
from markupsafe import Markup

from .loader import ThemeLoader
from .schema import GROUP_LABELS, ThemeMetadata

# Package directory (where theme subdirectories live)
THEMES_DIR = Path(__file__).parent


class ThemeRegistry:
    """Central registry for theme management.

    This is a singleton class that manages all theme loading, caching,
    and provides methods for Flask integration.
    """

    _instance: "ThemeRegistry | None" = None
    _loader: "ThemeLoader"
    _initialized: bool

    def __new__(cls) -> "ThemeRegistry":
        """Ensure singleton pattern."""
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._loader = ThemeLoader(THEMES_DIR)
            cls._instance._initialized = False
        return cls._instance

    @property
    def themes(self) -> dict[str, ThemeMetadata]:
        """Get all loaded themes."""
        return self._loader.load_all_themes()

    def get_theme(self, theme_id: str) -> ThemeMetadata | None:
        """Get a specific theme by ID.

        Args:
            theme_id: The theme identifier (e.g., "nord", "dracula")

        Returns:
            ThemeMetadata object or None if not found
        """
        return self.themes.get(theme_id)

    def get_theme_ids(self) -> list[str]:
        """Get sorted list of all theme IDs.

        Returns:
            List of theme ID strings
        """
        return sorted(self.themes.keys())

    def get_themes_by_group(self) -> dict[str, list[ThemeMetadata]]:
        """Get themes organized by group.

        Returns:
            Dictionary mapping group names to lists of ThemeMetadata
        """
        grouped: dict[str, list[ThemeMetadata]] = {}
        for theme in self.themes.values():
            grouped.setdefault(theme.group, []).append(theme)
        # Sort themes within each group by label
        for group in grouped:
            grouped[group].sort(key=lambda t: t.label)
        return grouped

    def get_combined_css(self) -> str:
        """Generate combined CSS from all theme files.

        Strips frontmatter and concatenates all theme CSS.

        Returns:
            Combined CSS string
        """
        css_parts: list[str] = []

        # Add header comment
        css_parts.append(
            "/* Auto-generated theme CSS - Do not edit directly */"
        )
        css_parts.append(
            f"/* Generated from {len(self.themes)} theme files */\n"
        )

        # Process themes in group order for predictable output
        group_order = ["core", "nature", "dev", "research", "other"]
        for group in group_order:
            group_themes = [t for t in self.themes.values() if t.group == group]
            if not group_themes:
                continue

            css_parts.append(
                f"\n/* === {GROUP_LABELS.get(group, group)} === */\n"
            )

            for theme in sorted(group_themes, key=lambda t: t.label):
                if theme.css_path and theme.css_path.exists():
                    content = self._loader.get_css_content(theme)
                    if content:
                        css_parts.append(f"/* Theme: {theme.label} */")
                        css_parts.append(content)
                        css_parts.append("")  # Empty line between themes

        return "\n".join(css_parts)

    def get_themes_json(self) -> Markup:
        """Get theme ID list as JSON for JavaScript.

        Returns:
            Markup-safe JSON array string
        """
        return Markup(json.dumps(self.get_theme_ids()))

    def get_metadata_json(self) -> Markup:
        """Get full theme metadata as JSON for JavaScript.

        Returns:
            Markup-safe JSON object string with theme metadata
        """
        metadata = {}
        for theme_id, theme in self.themes.items():
            metadata[theme_id] = theme.to_dict()
        return Markup(json.dumps(metadata))

    def get_settings_options(self) -> list[dict]:
        """Generate options list for settings UI.

        Returns:
            List of {label, value} dicts suitable for default_settings.json format
        """
        options = []
        for theme in self.themes.values():
            options.append(
                {
                    "label": theme.label,
                    "value": theme.id,
                }
            )
        return sorted(options, key=lambda x: x["label"])

    def get_grouped_settings_options(self) -> list[dict]:
        """Generate grouped options for settings UI with optgroup support.

        Returns:
            List of {label, value, group} dicts
        """
        options = []
        for theme in self.themes.values():
            options.append(
                {
                    "label": theme.label,
                    "value": theme.id,
                    "group": GROUP_LABELS.get(theme.group, theme.group),
                }
            )
        return sorted(options, key=lambda x: (x["group"], x["label"]))

    def is_valid_theme(self, theme_id: str) -> bool:
        """Check if a theme ID is valid.

        Args:
            theme_id: The theme identifier to validate

        Returns:
            True if theme exists, False otherwise
        """
        return theme_id in self.themes

    def clear_cache(self) -> None:
        """Clear theme cache (useful for development/hot-reload)."""
        self._loader.clear_cache()
        logger.debug("Theme cache cleared")


# Singleton instance
theme_registry = ThemeRegistry()


# Flask integration functions (for backward compatibility with theme_helper pattern)
def get_themes() -> list[str]:
    """Get list of available theme names.

    Returns:
        Sorted list of theme ID strings
    """
    return theme_registry.get_theme_ids()


def get_themes_json() -> Markup:
    """Get themes as JSON string for embedding in HTML.

    Returns:
        Markup-safe JSON array of theme IDs
    """
    return theme_registry.get_themes_json()


def get_theme_metadata() -> Markup:
    """Get full theme metadata as JSON for JavaScript.

    Returns:
        Markup-safe JSON object with theme metadata
    """
    return theme_registry.get_metadata_json()


__all__ = [
    "ThemeRegistry",
    "ThemeMetadata",
    "theme_registry",
    "get_themes",
    "get_themes_json",
    "get_theme_metadata",
    "THEMES_DIR",
    "GROUP_LABELS",
]
