"""Adapter connecting PolicyEngine with DesignResolutionEngine.

This module bridges the policy system with the design resolution engine,
allowing policies to configure typography, spacing, and color settings.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Dict, Optional

from tokenmoulds.design.engine import (
    DesignResolutionEngine,
    LineHeightMode,
    ResolvedDesign,
    ScaleRatio,
)
from tokenmoulds.design.policy.engine import PolicyContext, PolicyEngine
from tokenmoulds.design.policy.rules import Policy

if TYPE_CHECKING:
    from tokenmoulds.design.page_geometry import PageGeometry


# Map policy scale ratio names to ScaleRatio enum
SCALE_RATIO_MAP = {
    "minor_second": ScaleRatio.MINOR_SECOND,
    "major_second": ScaleRatio.MAJOR_SECOND,
    "minor_third": ScaleRatio.MINOR_THIRD,
    "major_third": ScaleRatio.MAJOR_THIRD,
    "perfect_fourth": ScaleRatio.PERFECT_FOURTH,
    "augmented_fourth": ScaleRatio.AUGMENTED_FOURTH,
    "perfect_fifth": ScaleRatio.PERFECT_FIFTH,
    "golden_ratio": ScaleRatio.GOLDEN_RATIO,
}


@dataclass
class DesignConfig:
    """Configuration for design resolution derived from policy."""

    # Typography
    base_size_pt: float = 12.0
    scale_ratio: ScaleRatio | None = None
    line_height_mode: LineHeightMode = LineHeightMode.SNAPPED
    line_height_multiplier: float = 1.4

    # Spacing
    density: str = "normal"
    baseline_snap: bool = True

    # Color
    min_contrast_ratio: float = 4.5
    dark_mode: bool = False

    @classmethod
    def from_policy_context(cls, ctx: PolicyContext) -> DesignConfig:
        """Create DesignConfig from evaluated policy context."""
        # Typography options
        typo_opts = ctx.get("typography", {}) or {}
        scale_ratio_name = typo_opts.get("scale_ratio", "major_third")
        scale_ratio = SCALE_RATIO_MAP.get(scale_ratio_name)

        line_height_mode_str = typo_opts.get("line_height_mode", "snapped")
        line_height_mode = (
            LineHeightMode.SNAPPED
            if line_height_mode_str == "snapped"
            else LineHeightMode.MULTIPLIER
        )

        # Spacing options
        spacing_opts = ctx.get("spacing", {}) or {}

        # Color options
        color_opts = ctx.get("color", {}) or {}

        return cls(
            base_size_pt=typo_opts.get("base_size_pt", 12.0),
            scale_ratio=scale_ratio,
            line_height_mode=line_height_mode,
            line_height_multiplier=typo_opts.get("line_height_multiplier", 1.4),
            density=spacing_opts.get("density", "normal"),
            baseline_snap=spacing_opts.get("baseline_snap", True),
            min_contrast_ratio=color_opts.get("min_contrast_ratio", 4.5),
            dark_mode=color_opts.get("dark_mode", False),
        )


class PolicyAwareDesignEngine:
    """Design engine that uses policy configuration.

    This class wraps DesignResolutionEngine with policy-based configuration,
    allowing design decisions to be driven by named policy presets.

    Example:
        # Create with default policy
        engine = PolicyAwareDesignEngine(fonts=fonts, brand=brand)
        design = engine.resolve()

        # Create with specific policy
        engine = PolicyAwareDesignEngine(
            fonts=fonts,
            brand=brand,
            policy="accessible",
        )
        design = engine.resolve()

    """

    def __init__(
        self,
        fonts,
        brand,
        locale: str = "en-US",
        colors: Dict | None = None,
        *,
        policy: str | Policy = "default",
        page_geometry: Optional[PageGeometry] = None,
    ) -> None:
        """Initialize policy-aware design engine.

        Args:
            fonts: Font configuration with metrics
            brand: Brand configuration (tone, density)
            locale: Locale code
            colors: Color input configuration
            policy: Policy name or Policy object
            page_geometry: Optional page geometry for layout calculations
        """
        self.fonts = fonts
        self.brand = brand
        self.locale = locale
        self.colors_input = colors or {}
        self.page_geometry = page_geometry

        # Set up policy engine (no providers — policy options are used directly)
        self._policy_engine = PolicyEngine()

        # Configure policy
        self._policy_engine.set_policy(policy)

    def get_policy_context(self) -> PolicyContext:
        """Evaluate and return the policy context."""
        return self._policy_engine.evaluate()

    def get_design_config(self) -> DesignConfig:
        """Get design configuration from policy."""
        ctx = self.get_policy_context()
        return DesignConfig.from_policy_context(ctx)

    def resolve(self) -> ResolvedDesign:
        """Resolve design tokens using policy configuration."""
        config = self.get_design_config()

        # Create the underlying design engine with policy-derived settings
        engine = DesignResolutionEngine(
            fonts=self.fonts,
            brand=self.brand,
            locale=self.locale,
            colors=self.colors_input,
            base_font_size_pt=config.base_size_pt,
            scale_ratio=config.scale_ratio,
            line_height_mode=config.line_height_mode,
            line_height_multiplier=config.line_height_multiplier,
            page_geometry=self.page_geometry,
        )

        return engine.resolve()

    @property
    def policy(self) -> Policy:
        """Current policy."""
        return self._policy_engine.policy


def create_design_engine(
    fonts,
    brand,
    *,
    policy: str = "default",
    locale: str = "en-US",
    colors: Dict | None = None,
    page_geometry: Optional[PageGeometry] = None,
) -> PolicyAwareDesignEngine:
    """Factory function for creating a policy-aware design engine.

    This is the recommended way to create design engines for template generation.

    Args:
        fonts: Font configuration
        brand: Brand configuration
        policy: Policy preset name ("default", "compact", "accessible", "presentation")
        locale: Locale code
        colors: Color configuration
        page_geometry: Optional page geometry for layout calculations

    Returns:
        Configured PolicyAwareDesignEngine
    """
    return PolicyAwareDesignEngine(
        fonts=fonts,
        brand=brand,
        locale=locale,
        colors=colors,
        policy=policy,
        page_geometry=page_geometry,
    )


__all__ = [
    "PolicyAwareDesignEngine",
    "DesignConfig",
    "create_design_engine",
    "SCALE_RATIO_MAP",
]
