"""Configuration loader for themes and SuperThemes.

Loads aspect ratios, variant presets, and SuperTheme settings from
tokenmoulds.config.yaml or custom YAML files.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List

import yaml

from tokenmoulds.themes.aspect_ratios import (
    AspectRatio,
    AspectRatioCategory,
    ASPECT_RATIOS as BUILTIN_RATIOS,
)


# Default config file location
DEFAULT_CONFIG_PATH = (
    Path(__file__).parent.parent.parent.parent / "tokenmoulds.config.yaml"
)


@dataclass
class VariantPreset:
    """Design variant preset configuration."""

    key: str
    name: str
    description: str = ""
    policy: str = "default"
    overrides: Dict[str, Any] = field(default_factory=dict)


@dataclass
class SuperThemeConfig:
    """SuperTheme generation configuration."""

    default_ratios: List[str] = field(default_factory=lambda: ["16_9", "16_10", "4_3"])
    max_package_mb: float = 5.0
    max_variants: int = 10


@dataclass
class ThemesConfig:
    """Complete themes configuration."""

    aspect_ratios: Dict[str, AspectRatio] = field(default_factory=dict)
    aspect_ratio_aliases: Dict[str, str] = field(default_factory=dict)
    supertheme: SuperThemeConfig = field(default_factory=SuperThemeConfig)
    variant_presets: Dict[str, VariantPreset] = field(default_factory=dict)

    def get_aspect_ratio(self, key: str) -> AspectRatio:
        """Get aspect ratio by key or alias."""
        # Resolve alias
        resolved_key = self.aspect_ratio_aliases.get(key, key)

        # Check config-defined ratios first
        if resolved_key in self.aspect_ratios:
            return self.aspect_ratios[resolved_key]

        # Fall back to built-in ratios
        if resolved_key in BUILTIN_RATIOS:
            return BUILTIN_RATIOS[resolved_key]

        available = sorted(set(self.aspect_ratios.keys()) | set(BUILTIN_RATIOS.keys()))
        raise KeyError(
            f"Unknown aspect ratio '{key}'. Available: {', '.join(available)}"
        )

    def list_aspect_ratios(
        self,
        category: AspectRatioCategory | None = None,
        include_builtin: bool = True,
    ) -> List[AspectRatio]:
        """List all aspect ratios, optionally filtered."""
        ratios: Dict[str, AspectRatio] = {}

        # Add built-in ratios first
        if include_builtin:
            ratios.update(BUILTIN_RATIOS)

        # Config-defined ratios override built-in
        ratios.update(self.aspect_ratios)

        # Filter by category if specified
        result = list(ratios.values())
        if category:
            result = [r for r in result if r.category == category]

        # Remove duplicates and sort
        seen = set()
        unique = []
        for r in result:
            if r.key not in seen:
                seen.add(r.key)
                unique.append(r)

        return sorted(unique, key=lambda r: r.key)

    def get_variant_preset(self, key: str) -> VariantPreset:
        """Get variant preset by key."""
        if key not in self.variant_presets:
            available = ", ".join(sorted(self.variant_presets.keys()))
            raise KeyError(f"Unknown variant preset '{key}'. Available: {available}")
        return self.variant_presets[key]

    def list_variant_presets(self) -> List[VariantPreset]:
        """List all variant presets."""
        return sorted(self.variant_presets.values(), key=lambda v: v.key)


def _parse_aspect_ratio(key: str, data: Dict[str, Any]) -> AspectRatio:
    """Parse aspect ratio from config dict."""
    name = data.get("name", key)
    width = data.get("width", 0)
    height = data.get("height", 0)
    unit = data.get("unit", "emu").lower()
    category_str = data.get("category", "presentation").lower()
    description = data.get("description", "")

    # Parse category
    if category_str == "presentation":
        category = AspectRatioCategory.PRESENTATION
    elif category_str == "print":
        category = AspectRatioCategory.PRINT
    else:
        category = AspectRatioCategory.CUSTOM

    # Create aspect ratio based on unit
    if unit == "emu":
        return AspectRatio(
            name=name,
            key=key,
            width_emu=int(width),
            height_emu=int(height),
            category=category,
            description=description,
        )
    elif unit == "inches":
        return AspectRatio.from_inches(
            name=name,
            key=key,
            width_inches=float(width),
            height_inches=float(height),
            category=category,
            description=description,
        )
    elif unit == "mm":
        return AspectRatio.from_mm(
            name=name,
            key=key,
            width_mm=float(width),
            height_mm=float(height),
            category=category,
            description=description,
        )
    elif unit == "ratio":
        return AspectRatio.from_ratio(
            name=name,
            key=key,
            width_ratio=int(width),
            height_ratio=int(height),
            category=category,
            description=description,
        )
    else:
        raise ValueError(f"Unknown unit '{unit}' for aspect ratio '{key}'")


def _parse_variant_preset(key: str, data: Dict[str, Any]) -> VariantPreset:
    """Parse variant preset from config dict."""
    return VariantPreset(
        key=key,
        name=data.get("name", key),
        description=data.get("description", ""),
        policy=data.get("policy", "default"),
        overrides=data.get("overrides", {}),
    )


def _parse_supertheme_config(data: Dict[str, Any]) -> SuperThemeConfig:
    """Parse SuperTheme config from dict."""
    return SuperThemeConfig(
        default_ratios=data.get("default_ratios", ["16_9", "16_10", "4_3"]),
        max_package_mb=float(data.get("max_package_mb", 5.0)),
        max_variants=int(data.get("max_variants", 10)),
    )


def load_themes_config(
    config_path: Path | str | None = None,
    config_data: Dict[str, Any] | None = None,
) -> ThemesConfig:
    """Load themes configuration from YAML file or dict.

    Args:
        config_path: Path to YAML config file (defaults to tokenmoulds.config.yaml)
        config_data: Optional dict to use instead of loading from file

    Returns:
        ThemesConfig instance
    """
    if config_data is None:
        # Load from file
        if config_path is None:
            config_path = DEFAULT_CONFIG_PATH
        else:
            config_path = Path(config_path)

        if not config_path.exists():
            # Return defaults if no config file
            return ThemesConfig()

        with open(config_path, "r", encoding="utf-8") as f:
            full_config = yaml.safe_load(f) or {}

        config_data = full_config.get("themes") or {}

    assert config_data is not None
    # Parse aspect ratios
    aspect_ratios: Dict[str, AspectRatio] = {}
    for key, data in (config_data.get("aspect_ratios") or {}).items():
        if isinstance(data, dict):
            aspect_ratios[key] = _parse_aspect_ratio(key, data)

    # Parse aliases
    aliases = config_data.get("aspect_ratio_aliases") or {}

    # Parse SuperTheme config
    supertheme_data = config_data.get("supertheme") or {}
    supertheme = _parse_supertheme_config(supertheme_data)

    # Parse variant presets
    variant_presets: Dict[str, VariantPreset] = {}
    for key, data in (config_data.get("variant_presets") or {}).items():
        if isinstance(data, dict):
            variant_presets[key] = _parse_variant_preset(key, data)

    return ThemesConfig(
        aspect_ratios=aspect_ratios,
        aspect_ratio_aliases=aliases,
        supertheme=supertheme,
        variant_presets=variant_presets,
    )


# Global config instance (lazy loaded)
_config: ThemesConfig | None = None


def get_themes_config() -> ThemesConfig:
    """Get the global themes configuration (lazy loaded)."""
    global _config
    if _config is None:
        _config = load_themes_config()
    return _config


def reload_themes_config(config_path: Path | str | None = None) -> ThemesConfig:
    """Reload themes configuration from file."""
    global _config
    _config = load_themes_config(config_path)
    return _config


__all__ = [
    "ThemesConfig",
    "SuperThemeConfig",
    "VariantPreset",
    "load_themes_config",
    "get_themes_config",
    "reload_themes_config",
]
