"""Page helper registration for sx docs.

All helpers return data values (dicts, lists) — no sx_call(), no SxExpr.
Markup composition lives entirely in .sx files.
"""
from __future__ import annotations


def _register_sx_helpers() -> None:
    """Register Python data helpers as page helpers."""
    from shared.sx.pages import register_page_helpers
    from content.highlight import highlight as _highlight

    register_page_helpers("sx", {
        "highlight": _highlight,
        "primitives-data": _primitives_data,
        "reference-data": _reference_data,
        "attr-detail-data": _attr_detail_data,
        "spec-data": _spec_data,
    })


def _primitives_data() -> dict:
    """Return the PRIMITIVES dict for the primitives docs page."""
    from content.pages import PRIMITIVES
    return PRIMITIVES


def _reference_data(slug: str) -> dict:
    """Return reference table data for a given slug.

    Returns a dict whose keys become SX env bindings:
    - attributes: req-attrs, beh-attrs, uniq-attrs
    - headers: req-headers, resp-headers
    - events: events-list
    - js-api: js-api-list
    """
    from content.pages import (
        REQUEST_ATTRS, BEHAVIOR_ATTRS, SX_UNIQUE_ATTRS,
        REQUEST_HEADERS, RESPONSE_HEADERS,
        EVENTS, JS_API, ATTR_DETAILS,
    )

    if slug == "attributes":
        return {
            "req-attrs": [
                {"name": a, "desc": d, "exists": e,
                 "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
                for a, d, e in REQUEST_ATTRS
            ],
            "beh-attrs": [
                {"name": a, "desc": d, "exists": e,
                 "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
                for a, d, e in BEHAVIOR_ATTRS
            ],
            "uniq-attrs": [
                {"name": a, "desc": d, "exists": e,
                 "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
                for a, d, e in SX_UNIQUE_ATTRS
            ],
        }
    elif slug == "headers":
        return {
            "req-headers": [
                {"name": n, "value": v, "desc": d}
                for n, v, d in REQUEST_HEADERS
            ],
            "resp-headers": [
                {"name": n, "value": v, "desc": d}
                for n, v, d in RESPONSE_HEADERS
            ],
        }
    elif slug == "events":
        return {
            "events-list": [
                {"name": n, "desc": d}
                for n, d in EVENTS
            ],
        }
    elif slug == "js-api":
        return {
            "js-api-list": [
                {"name": n, "desc": d}
                for n, d in JS_API
            ],
        }
    # Default — return attrs data for fallback
    return {
        "req-attrs": [
            {"name": a, "desc": d, "exists": e,
             "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
            for a, d, e in REQUEST_ATTRS
        ],
        "beh-attrs": [
            {"name": a, "desc": d, "exists": e,
             "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
            for a, d, e in BEHAVIOR_ATTRS
        ],
        "uniq-attrs": [
            {"name": a, "desc": d, "exists": e,
             "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None}
            for a, d, e in SX_UNIQUE_ATTRS
        ],
    }


_CORE_SPECS = {
    "parser": ("parser.sx", "Parser", "Tokenization and parsing of SX source text into AST."),
    "evaluator": ("eval.sx", "Evaluator", "Tree-walking evaluation of SX expressions."),
    "primitives": ("primitives.sx", "Primitives", "All built-in pure functions and their signatures."),
    "renderer": ("render.sx", "Renderer", "Shared rendering registries and utilities used by all adapters."),
}

_ADAPTER_SPECS = {
    "adapter-dom": ("adapter-dom.sx", "DOM Adapter", "Renders SX expressions to live DOM nodes. Browser-only."),
    "adapter-html": ("adapter-html.sx", "HTML Adapter", "Renders SX expressions to HTML strings. Server-side."),
    "adapter-sx": ("adapter-sx.sx", "SX Wire Adapter", "Serializes SX for client-side rendering. Component calls stay unexpanded."),
    "engine": ("engine.sx", "SxEngine", "Fetch/swap/history engine for browser-side SX. Like HTMX but native to SX."),
}

_ALL_SPECS = {**_CORE_SPECS, **_ADAPTER_SPECS}


def _spec_data(slug: str) -> dict:
    """Return spec file source and metadata for display."""
    import os

    ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
    if not os.path.isdir(ref_dir):
        ref_dir = "/app/shared/sx/ref"

    base = {"spec-not-found": None, "spec-title": None, "spec-desc": None,
            "spec-filename": None, "spec-source": None, "spec-files": None}

    if slug == "core":
        specs = []
        for key in ("parser", "evaluator", "primitives", "renderer"):
            filename, title, desc = _CORE_SPECS[key]
            filepath = os.path.join(ref_dir, filename)
            source = _read_spec(filepath)
            specs.append({
                "title": title, "desc": desc, "filename": filename,
                "source": source, "href": f"/specs/{key}",
            })
        return {**base, "spec-title": "Core Language", "spec-files": specs}

    if slug == "adapters":
        specs = []
        for key in ("adapter-dom", "adapter-html", "adapter-sx", "engine"):
            filename, title, desc = _ADAPTER_SPECS[key]
            filepath = os.path.join(ref_dir, filename)
            source = _read_spec(filepath)
            specs.append({
                "title": title, "desc": desc, "filename": filename,
                "source": source, "href": f"/specs/{key}",
            })
        return {**base, "spec-title": "Adapters & Engine", "spec-files": specs}

    info = _ALL_SPECS.get(slug)
    if not info:
        return {**base, "spec-not-found": True}

    filename, title, desc = info
    filepath = os.path.join(ref_dir, filename)
    source = _read_spec(filepath)
    return {**base,
            "spec-title": title, "spec-desc": desc,
            "spec-filename": filename, "spec-source": source}


def _read_spec(filepath: str) -> str:
    """Read a spec file, returning empty string if missing."""
    try:
        with open(filepath, encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError:
        return ";; spec file not found"


def _attr_detail_data(slug: str) -> dict:
    """Return attribute detail data for a specific attribute slug.

    Returns a dict whose keys become SX env bindings:
    - attr-title, attr-description, attr-example, attr-handler
    - attr-demo (component call or None)
    - attr-wire-id (wire placeholder id or None)
    - attr-not-found (truthy if not found)
    """
    from content.pages import ATTR_DETAILS
    from shared.sx.helpers import SxExpr

    detail = ATTR_DETAILS.get(slug)
    if not detail:
        return {"attr-not-found": True}

    demo_name = detail.get("demo")
    wire_id = None
    if "handler" in detail:
        wire_id = f"ref-wire-{slug.replace(':', '-').replace('*', 'star')}"

    return {
        "attr-not-found": None,
        "attr-title": slug,
        "attr-description": detail["description"],
        "attr-example": detail["example"],
        "attr-handler": detail.get("handler"),
        "attr-demo": SxExpr(f"(~{demo_name})") if demo_name else None,
        "attr-wire-id": wire_id,
    }
