"""Public render/utility functions called from bp routes."""
from __future__ import annotations


def _component_source_text(*names: str) -> str:
    """Get defcomp source text for named components."""
    from shared.sx.jinja_bridge import _COMPONENT_ENV
    from shared.sx.types import Component
    from shared.sx.parser import serialize
    parts = []
    for name in names:
        key = name if name.startswith("~") else f"~{name}"
        val = _COMPONENT_ENV.get(key)
        if isinstance(val, Component):
            param_strs = ["&key"] + list(val.params)
            if val.has_children:
                param_strs.extend(["&rest", "children"])
            params_sx = "(" + " ".join(param_strs) + ")"
            body_sx = serialize(val.body, pretty=True)
            parts.append(f"(defcomp ~{val.name} {params_sx}\n{body_sx})")
    return "\n\n".join(parts)


def _oob_code(target_id: str, text: str) -> str:
    """OOB swap that displays plain code in a styled block."""
    from shared.sx.helpers import sx_call
    return sx_call("doc-oob-code", target_id=target_id, text=text)


def _full_wire_text(sx_src: str, *comp_names: str) -> str:
    """Build the full wire response text showing component defs + CSS note + sx source.

    Only includes component definitions the client doesn't already have,
    matching the real behaviour of sx_response().
    """
    from quart import request
    parts = []
    if comp_names:
        # Check which components the client already has
        loaded_raw = request.headers.get("SX-Components", "")
        loaded = set(loaded_raw.split(",")) if loaded_raw else set()
        missing = [n for n in comp_names
                   if f"~{n}" not in loaded and n not in loaded]
        if missing:
            comp_text = _component_source_text(*missing)
            if comp_text:
                parts.append(f'<script type="text/sx" data-components>\n{comp_text}\n</script>')
    parts.append('<style data-sx-css>/* new CSS rules */</style>')
    # Pretty-print the sx source for readable display
    try:
        from shared.sx.parser import parse as _parse, serialize as _serialize
        parts.append(_serialize(_parse(sx_src), pretty=True))
    except Exception:
        parts.append(sx_src)
    return "\n\n".join(parts)
