"""Renderer resource loader for Prefab.

Ships a pre-built, self-contained HTML file (all JS/CSS inlined) inside the
Python package.  `get_renderer_html()` reads and returns it directly — no
external server, CDN, or CSP domains required.

Set `PREFAB_RENDERER_URL` to load renderer assets from an external origin
instead — useful for local development with `npx vite preview` or a CDN:

```bash
PREFAB_RENDERER_URL=http://localhost:4173 uv run python my_server.py
```
"""

from __future__ import annotations

import os
from pathlib import Path
from urllib.parse import urlparse

_BUNDLED_HTML = Path(__file__).parent / "app.html"

PYODIDE_CDN_ORIGIN = "https://cdn.jsdelivr.net"

_EXTERNAL_HEAD = """\
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Prefab</title>
  <link rel="stylesheet" crossorigin href="{base_url}/assets/renderer.css">
  <script type="module" crossorigin src="{base_url}/assets/renderer.js"></script>"""

_EXTERNAL_TEMPLATE = """\
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Prefab</title>
  <link rel="stylesheet" crossorigin href="{base_url}/assets/renderer.css">
</head>
<body>
  <div id="root"></div>
  <script type="module" crossorigin src="{base_url}/assets/renderer.js"></script>
</body>
</html>
"""


def _get_origin(url: str) -> str:
    """Extract the origin (scheme + host + port) from a URL."""
    parsed = urlparse(url)
    origin = f"{parsed.scheme}://{parsed.hostname}"
    if parsed.port:
        origin += f":{parsed.port}"
    return origin


def get_renderer_head() -> str:
    """Return the renderer `<head>` content (JS, CSS, meta tags).

    For bundled mode, extracts everything between `<head>` and
    `</head>` from the self-contained HTML bundle.  For external mode,
    returns `<link>`/`<script>` tags pointing at the external URL.
    """
    override = os.environ.get("PREFAB_RENDERER_URL")
    if override:
        return _EXTERNAL_HEAD.format(base_url=override.rstrip("/"))
    html = _BUNDLED_HTML.read_text(encoding="utf-8")
    head_start = html.index("<head>") + len("<head>")
    # The bundled JS contains HTML string literals (e.g. "<head></head><body>"),
    # so we must search for </head> *after* the first real </script> tag.
    # Vite escapes </script> inside inline scripts as <\/script>, so the first
    # literal </script> in the file is always the actual closing tag.
    script_end = html.index("</script>")
    head_end = html.index("</head>", script_end)
    return html[head_start:head_end].rstrip()


def get_renderer_html() -> str:
    """Return the renderer HTML.

    By default, returns the bundled single-file HTML with all JS/CSS
    inlined.  When `PREFAB_RENDERER_URL` is set, returns a lightweight
    stub that loads assets from that external origin.
    """
    override = os.environ.get("PREFAB_RENDERER_URL")
    if override:
        return _EXTERNAL_TEMPLATE.format(base_url=override.rstrip("/"))
    return _BUNDLED_HTML.read_text(encoding="utf-8")


def get_renderer_csp() -> dict[str, list[str]]:
    """Return CSP domains needed for the renderer to load.

    The bundled renderer is fully self-contained, so no CSP domains are
    needed.  When `PREFAB_RENDERER_URL` is set, returns the external
    origin so the host sandbox allows loading those assets.
    """
    override = os.environ.get("PREFAB_RENDERER_URL")
    if override:
        return {"resource_domains": [_get_origin(override.rstrip("/"))]}
    return {"resource_domains": []}


def get_generative_renderer_html() -> str:
    """Return the generative renderer HTML.

    Returns the same bundled renderer as `get_renderer_html()`. The
    renderer is generative-capable (Pyodide + streaming bridge), but
    the generative code is inert unless the host sends
    `ontoolinputpartial`. The CSP requirements differ — use
    `get_generative_renderer_csp()` for hosts that use generative features.
    """
    return get_renderer_html()


def get_generative_renderer_csp() -> dict[str, list[str]]:
    """Return CSP domains needed for the generative renderer.

    Includes the Pyodide CDN origin (jsdelivr) for both resource loading
    (script tags) and connect (fetch for WASM binary and packages).
    """
    domains = [PYODIDE_CDN_ORIGIN]
    override = os.environ.get("PREFAB_RENDERER_URL")
    if override:
        domains.append(_get_origin(override.rstrip("/")))
    return {
        "resource_domains": domains,
        "connect_domains": [
            PYODIDE_CDN_ORIGIN,
            "https://pypi.org",
            "https://files.pythonhosted.org",
        ],
    }
