"""Token calculation functions extracted from AdvancedTokenEngine."""

from __future__ import annotations

from typing import Any, Dict, Mapping

from tokenmoulds.colors.transforms import (
    darken,
    desaturate,
    hex_to_hsl,
    hsl_rotate,
    hsl_to_hex,
)
from tokenmoulds.design.color_defaults import (
    TEXT_INVERSE as _TEXT_INVERSE,
    TEXT_MUTED as _TEXT_MUTED,
    TEXT_PRIMARY as _TEXT_PRIMARY,
    TEXT_SECONDARY as _TEXT_SECONDARY,
)
from tokenmoulds.design.engine import ResolvedDesign
from tokenmoulds.dtcg.layout_recipe_resolver import (
    compute_default_slide_regions as _compute_slide_regions,
)
from tokenmoulds.dtcg.token_builders import build_color_tokens


def calculate_typography(
    *,
    resolved_design: ResolvedDesign,
    font_pair: Mapping[str, str],
    mono_font: str,
) -> Dict[str, Any]:
    """Build typography tokens from the resolved modular type scale."""
    design = resolved_design

    # Build scale_emu from the resolved type scale (baseline-snapped)
    scale_emu: Dict[str, int] = {}
    for step in design.type_scale:
        scale_emu[step.name] = step.size_emu

    # Build line heights from resolved roles
    body_role = design.roles.get("text.body.primary")
    body_lh = body_role.line_height_multiplier if body_role else 1.4

    return {
        "scale_emu": scale_emu,
        "families": {
            "sans": font_pair.get("sans", "Inter"),
            "serif": font_pair.get("serif", "PT Serif"),
            "mono": mono_font,
        },
        "weights": {
            "light": 300,
            "regular": 400,
            "medium": 500,
            "semibold": 600,
            "bold": 700,
        },
        "line_heights": {
            "tight": 1.2,
            "normal": round(body_lh, 2),
            "loose": 1.6,
        },
    }


def calculate_colors(
    *,
    base_colors: Mapping[str, str],
) -> Dict[str, Any]:
    """Build color tokens from base colors using color theory."""
    primary_hsl = hex_to_hsl(base_colors["primary"])

    triadic_1_hsl = hsl_rotate(primary_hsl, 120)
    triadic_2_hsl = hsl_rotate(primary_hsl, 240)

    split_1_hsl = hsl_rotate(primary_hsl, 60)
    split_2_hsl = hsl_rotate(primary_hsl, 300)

    neutral_hsl = desaturate(primary_hsl, 0.9)

    return {
        "palette": {
            "primary": base_colors["primary"],
            "secondary": base_colors["secondary"],
            "tertiary": hsl_to_hex(triadic_1_hsl),
            "quaternary": hsl_to_hex(triadic_2_hsl),
            "accent_1": hsl_to_hex(split_1_hsl),
            "accent_2": hsl_to_hex(split_2_hsl),
        },
        "semantic": {
            "success": hsl_to_hex(triadic_2_hsl),
            "warning": hsl_to_hex(split_1_hsl),
            "error": base_colors["secondary"],
            "info": base_colors["primary"],
        },
        "surfaces": {
            "white": hsl_to_hex([neutral_hsl["h"], 5, 98]),
            "lightest": hsl_to_hex([neutral_hsl["h"], 10, 95]),
            "light": hsl_to_hex([neutral_hsl["h"], 15, 85]),
            "medium": hsl_to_hex([neutral_hsl["h"], 25, 65]),
            "dark": hsl_to_hex([neutral_hsl["h"], 35, 35]),
            "darkest": hsl_to_hex([neutral_hsl["h"], 45, 15]),
            "black": hsl_to_hex([neutral_hsl["h"], 50, 5]),
        },
        "text": {
            "primary": _TEXT_PRIMARY,
            "secondary": _TEXT_SECONDARY,
            "tertiary": _TEXT_MUTED,
            "inverse": _TEXT_INVERSE,
            "link": darken(base_colors["primary"], 0.15),
            "link_visited": darken(base_colors["primary"], 0.25),
        },
    }


def calculate_spacing(
    *,
    resolved_design: ResolvedDesign,
) -> Dict[str, Any]:
    """Build spacing tokens from the resolved baseline-grid spacing scale."""
    from tokenmoulds.design.units import pt_to_emu

    spacing = resolved_design.spacing
    scale_emu: Dict[str, int] = {}
    for name, pt_val in spacing.scale.items():
        scale_emu[name] = pt_to_emu(pt_val)

    semantic_emu = {
        "paragraph": spacing.get_emu("paragraph"),
        "section": spacing.get_emu("section"),
        "page": spacing.get_emu("page"),
    }

    return {
        "scale_emu": scale_emu,
        "semantic": semantic_emu,
    }


def calculate_kerning(
    *,
    resolved_design: ResolvedDesign,
    baseline_emu: int,
) -> Dict[str, Any]:
    """Build kerning tokens from resolved role typography."""
    # Extract kerning from resolved roles
    element_kerning: Dict[str, int] = {}
    for role_name, role_typo in resolved_design.roles.items():
        if role_name.startswith("display"):
            element_kerning.setdefault("heading", role_typo.kerning_emu)
        elif role_name == "text.body.primary":
            element_kerning["body"] = role_typo.kerning_emu
        elif role_name == "text.ui":
            element_kerning["ui"] = role_typo.kerning_emu
        elif role_name.startswith("text.table"):
            element_kerning.setdefault("table", role_typo.kerning_emu)

    body_kerning = element_kerning.get("body", baseline_emu // 200)
    element_kerning.setdefault("heading", int(body_kerning * 0.8))
    element_kerning.setdefault("ui", int(body_kerning * 1.1))
    element_kerning.setdefault("table", int(body_kerning * 0.95))
    element_kerning["caps"] = int(body_kerning * 1.8)

    return {
        "base_unit_emu": body_kerning,
        "element_kerning_emu": element_kerning,
    }


def calculate_layout(
    *,
    baseline_emu: int,
    locale_settings: Mapping[str, Any],
    brand_tone: float = 0.5,
) -> Dict[str, Any]:
    """Build layout tokens for slide dimensions, margins, and content areas."""
    slide_dimensions = {
        "16:9": {"width": 9144000, "height": 5143500},
        "16:10": {"width": 9144000, "height": 5715000},
        "4:3": {"width": 9144000, "height": 6858000},
    }

    margins = {
        "16:9": {"x": baseline_emu * 8, "y": baseline_emu * 6},
        "16:10": {"x": baseline_emu * 8, "y": baseline_emu * 8},
        "4:3": {"x": baseline_emu * 10, "y": baseline_emu * 8},
    }

    content_areas: Dict[str, Dict[str, int]] = {}
    for ratio in slide_dimensions:
        content_areas[ratio] = {
            "width": slide_dimensions[ratio]["width"] - (margins[ratio]["x"] * 2),
            "height": slide_dimensions[ratio]["height"] - (margins[ratio]["y"] * 2),
        }

    is_rtl = locale_settings.get("text_direction") == "rtl"
    supports_vertical = locale_settings.get("vertical_writing", False)

    return {
        "slide_dimensions": slide_dimensions,
        "margins": margins,
        "content_areas": content_areas,
        "grid": {
            "columns": 12,
            "gutter": baseline_emu * 2,
            "direction": "rtl" if is_rtl else "ltr",
            "reading_order": locale_settings.get("reading_order", "left-to-right"),
        },
        "text_flow": {
            "direction": locale_settings.get("text_direction", "ltr"),
            "vertical_writing": supports_vertical,
            "line_break_rules": locale_settings.get("line_break_rules", "standard"),
            "bidi_support": locale_settings.get("bidi_support", False),
        },
        "slide": {
            "regions": _compute_slide_regions(baseline_emu, brand_tone=brand_tone),
        },
    }


def calculate_components(
    *,
    typography: Mapping[str, Any],
    colors: Mapping[str, Any],
    spacing: Mapping[str, Any],
    layout: Mapping[str, Any],
    locale: Mapping[str, Any],
    baseline_emu: int,
    base_colors: Mapping[str, str],
) -> Dict[str, Any]:
    """Generate reusable component tokens derived from base scales."""
    scale_emu = typography.get("scale_emu", {})
    families = typography.get("families", {})
    weights = typography.get("weights", {})
    line_heights = typography.get("line_heights", {})

    from tokenmoulds.design.color_defaults import (
        SURFACE_LIGHTEST,
        SURFACE_WHITE,
    )

    palette = colors.get("palette", {})
    surfaces = colors.get("surfaces", {})
    semantic = colors.get("semantic", {})
    text_colors = colors.get("text", {})

    spacing_scale = spacing.get("scale_emu", {})
    spacing_semantic = spacing.get("semantic", {})

    baseline_emu = int(baseline_emu)
    radius_emu = max(1, baseline_emu // 8)
    border_emu = max(1, baseline_emu // 32)

    slide_margins = layout.get("margins", {})
    grid = layout.get("grid", {})

    return {
        "button": {
            "primary": {
                "background": palette.get("primary", base_colors["primary"]),
                "text": text_colors.get("inverse", _TEXT_INVERSE),
                "border": palette.get("primary", base_colors["primary"]),
                "radius_emu": radius_emu,
                "border_emu": border_emu,
                "padding_x_emu": spacing_scale.get("small", baseline_emu),
                "padding_y_emu": spacing_scale.get("tiny", baseline_emu // 2),
                "font_family": families.get("sans", "Inter"),
                "font_weight": weights.get("semibold", 600),
                "font_size_emu": scale_emu.get("body", baseline_emu),
                "line_height": line_heights.get("normal", 1.4),
            },
            "secondary": {
                "background": palette.get("secondary", base_colors["secondary"]),
                "text": text_colors.get("inverse", _TEXT_INVERSE),
                "border": palette.get("secondary", base_colors["secondary"]),
                "radius_emu": radius_emu,
                "border_emu": border_emu,
                "padding_x_emu": spacing_scale.get("small", baseline_emu),
                "padding_y_emu": spacing_scale.get("tiny", baseline_emu // 2),
                "font_family": families.get("sans", "Inter"),
                "font_weight": weights.get("semibold", 600),
                "font_size_emu": scale_emu.get("body", baseline_emu),
                "line_height": line_heights.get("normal", 1.4),
            },
            "ghost": {
                "background": surfaces.get("white", SURFACE_WHITE),
                "text": palette.get("primary", base_colors["primary"]),
                "border": palette.get("primary", base_colors["primary"]),
                "radius_emu": radius_emu,
                "border_emu": border_emu,
                "padding_x_emu": spacing_scale.get("small", baseline_emu),
                "padding_y_emu": spacing_scale.get("tiny", baseline_emu // 2),
                "font_family": families.get("sans", "Inter"),
                "font_weight": weights.get("regular", 400),
                "font_size_emu": scale_emu.get("body", baseline_emu),
                "line_height": line_heights.get("normal", 1.4),
            },
        },
        "card": {
            "background": surfaces.get("white", SURFACE_WHITE),
            "border": surfaces.get("light", SURFACE_LIGHTEST),
            "radius_emu": radius_emu,
            "border_emu": border_emu,
            "padding_emu": spacing_scale.get("medium", baseline_emu * 2),
        },
        "table": {
            "header_fill": palette.get("primary", base_colors["primary"]),
            "header_text": text_colors.get("inverse", _TEXT_INVERSE),
            "row_fill": surfaces.get("lightest", SURFACE_WHITE),
            "row_text": text_colors.get("primary", _TEXT_PRIMARY),
            "border": surfaces.get("light", SURFACE_LIGHTEST),
            "border_emu": border_emu,
            "row_height_emu": spacing_scale.get("large", baseline_emu * 4),
            "cell_padding_emu": spacing_scale.get("tiny", baseline_emu // 2),
        },
        "callout": {
            "background": surfaces.get("lightest", SURFACE_WHITE),
            "border": semantic.get("info", base_colors["primary"]),
            "border_emu": border_emu,
            "radius_emu": radius_emu,
            "padding_emu": spacing_scale.get("small", baseline_emu),
            "text": text_colors.get("primary", _TEXT_PRIMARY),
        },
        "list": {
            "indent_emu": spacing_scale.get("small", baseline_emu),
            "hanging_emu": spacing_scale.get("micro", max(1, baseline_emu // 4)),
            "paragraph_spacing_emu": spacing_semantic.get("paragraph", baseline_emu),
        },
        "slide": {
            "margins": slide_margins,
            "columns": grid.get("columns", 12),
            "gutter_emu": grid.get("gutter", baseline_emu * 2),
        },
        "locale": {
            "paper_size": locale.get("paper_size", "A4"),
            "units": locale.get("units", "metric"),
            "text_direction": locale.get("text_direction", "ltr"),
        },
    }


def calculate_ooxml_mappings(
    *,
    typography: Mapping[str, Any],
    colors: Mapping[str, Any],
    locale: Mapping[str, Any],
    locale_code: str,
    font_pair: Mapping[str, str],
    base_colors: Mapping[str, str],
) -> Dict[str, Any]:
    """Generate OOXML-specific theme and font mappings."""
    theme_tokens = build_color_tokens({"colors": colors}, base_colors)
    theme_mapping = theme_tokens.get("theme_mapping", {})

    families = typography.get("families", {})
    major_font = (
        font_pair.get("major") or font_pair.get("sans") or families.get("sans", "Inter")
    )
    minor_font = (
        font_pair.get("minor") or font_pair.get("sans") or families.get("sans", "Inter")
    )

    fonts = {
        "major": major_font,
        "minor": minor_font,
        "serif": font_pair.get("serif", families.get("serif", "Roboto Slab")),
        "sans": families.get("sans", "Inter"),
        "mono": families.get("mono", "Consolas"),
    }

    return {
        "theme": {
            "name": "TokenMoulds Generated",
            "color_scheme_name": "TokenMoulds Colors",
            "font_scheme_name": "TokenMoulds Fonts",
            "effect_scheme_name": "TokenMoulds Effects",
        },
        "colors": theme_mapping,
        "fonts": fonts,
        "language": {
            "locale": locale_code,
            "text_direction": locale.get("text_direction", "ltr"),
            "reading_order": locale.get("reading_order", "left-to-right"),
        },
    }
