"""Policy rules and presets for design decisions."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Mapping


@dataclass(frozen=True)
class Policy:
    """A named collection of policy options."""

    name: str
    description: str
    options: Mapping[str, Any] = field(default_factory=dict)


# Typography policy options
TYPOGRAPHY_OPTIONS = {
    "scale_ratio": "major_third",  # minor_second, major_second, minor_third, major_third, perfect_fourth, golden_ratio
    "base_size_pt": 12.0,
    "line_height_mode": "snapped",  # snapped, multiplier
    "line_height_multiplier": 1.4,
    "heading_line_height": 1.2,
}

# Color policy options
COLOR_OPTIONS = {
    "contrast_mode": "wcag_aa",  # wcag_aa, wcag_aaa, apca
    "min_contrast_ratio": 4.5,
    "color_space": "oklch",  # srgb, oklch, oklab
    "dark_mode": False,
}

# Spacing policy options
SPACING_OPTIONS = {
    "density": "normal",  # compact, normal, relaxed
    "baseline_snap": True,
    "paragraph_spacing_multiplier": 1.0,
}

# Font embedding policy options
FONT_EMBEDDING_OPTIONS = {
    "embed_fonts": True,
    "subset_fonts": True,
    "obfuscation": "odttf",  # odttf, none
    "fallback_fonts": ["Arial", "Helvetica", "sans-serif"],
}

# Accessibility policy options
ACCESSIBILITY_OPTIONS = {
    "enforce_contrast": True,
    "min_font_size_pt": 9.0,
    "require_alt_text": True,
    "color_blind_safe": False,
}


# Pre-defined policy presets
POLICY_PRESETS: dict[str, Policy] = {
    "default": Policy(
        name="default",
        description="Balanced defaults for general documents",
        options={
            "typography": TYPOGRAPHY_OPTIONS,
            "color": COLOR_OPTIONS,
            "spacing": SPACING_OPTIONS,
            "font_embedding": FONT_EMBEDDING_OPTIONS,
            "accessibility": ACCESSIBILITY_OPTIONS,
        },
    ),
    "compact": Policy(
        name="compact",
        description="Dense layout for data-heavy documents",
        options={
            "typography": {
                **TYPOGRAPHY_OPTIONS,
                "scale_ratio": "minor_second",
                "base_size_pt": 10.0,
            },
            "color": COLOR_OPTIONS,
            "spacing": {**SPACING_OPTIONS, "density": "compact"},
            "font_embedding": FONT_EMBEDDING_OPTIONS,
            "accessibility": ACCESSIBILITY_OPTIONS,
        },
    ),
    "accessible": Policy(
        name="accessible",
        description="Maximum accessibility compliance",
        options={
            "typography": {
                **TYPOGRAPHY_OPTIONS,
                "base_size_pt": 14.0,
                "line_height_multiplier": 1.5,
            },
            "color": {
                **COLOR_OPTIONS,
                "contrast_mode": "wcag_aaa",
                "min_contrast_ratio": 7.0,
            },
            "spacing": {**SPACING_OPTIONS, "density": "relaxed"},
            "font_embedding": FONT_EMBEDDING_OPTIONS,
            "accessibility": {
                **ACCESSIBILITY_OPTIONS,
                "min_font_size_pt": 12.0,
                "color_blind_safe": True,
            },
        },
    ),
    "presentation": Policy(
        name="presentation",
        description="Optimized for slides and presentations",
        options={
            "typography": {
                **TYPOGRAPHY_OPTIONS,
                "scale_ratio": "perfect_fourth",
                "base_size_pt": 18.0,
            },
            "color": COLOR_OPTIONS,
            "spacing": {**SPACING_OPTIONS, "density": "relaxed"},
            "font_embedding": FONT_EMBEDDING_OPTIONS,
            "accessibility": ACCESSIBILITY_OPTIONS,
        },
    ),
}

DEFAULT_POLICY = POLICY_PRESETS["default"]


def load_policy(name: str) -> Policy:
    """Load a policy by name."""
    if name in POLICY_PRESETS:
        return POLICY_PRESETS[name]
    raise ValueError(
        f"Unknown policy: {name!r}. Available: {list(POLICY_PRESETS.keys())}"
    )


def merge_policy(base: Policy, overrides: Mapping[str, Any]) -> Policy:
    """Create a new policy by merging overrides into a base policy."""
    merged_options = dict(base.options)
    for key, value in overrides.items():
        if (
            key in merged_options
            and isinstance(merged_options[key], dict)
            and isinstance(value, dict)
        ):
            merged_options[key] = {**merged_options[key], **value}
        else:
            merged_options[key] = value

    return Policy(
        name=f"{base.name}_custom",
        description=f"Custom policy based on {base.name}",
        options=merged_options,
    )


__all__ = [
    "Policy",
    "POLICY_PRESETS",
    "DEFAULT_POLICY",
    "load_policy",
    "merge_policy",
    "TYPOGRAPHY_OPTIONS",
    "COLOR_OPTIONS",
    "SPACING_OPTIONS",
    "FONT_EMBEDDING_OPTIONS",
    "ACCESSIBILITY_OPTIONS",
]
