"""Doc scenario Test D -- form persistence + admin retrieval.

Given: user asks for a form; submissions must be saved; admin must view them.
Expect: writes go through Cloud, public visitors can create but not arbitrarily read,
and the staff read path is actually gated (not just documented as gated).

Asserts on the real generated source contact_adapter_files produces, not a test
double standing in for it -- the same shared adapter file backs both the public create
route and the staff read route, so this also proves the split is enforced in one place,
not duplicated (and possibly forgotten) across two.
"""
from __future__ import annotations

import re

from src.domain.codegen.contact_adapter import contact_adapter_files
from src.domain.projects.runtime_invariants import ProjectRuntimeInvariants, extract_runtime_invariants


def _signature(source: str, fn_name: str) -> str:
    match = re.search(rf"export\s+(?:async\s+)?function\s+{fn_name}\s*\(([^)]*)\)", source)
    assert match, f"{fn_name} not found"
    return match.group(1)


def test_persistence_requirement_is_inferred_without_the_user_saying_cloud():
    invariants = extract_runtime_invariants(
        "Create a contact form and let the admin view submissions.",
        ProjectRuntimeInvariants(),
    )
    assert invariants.persistence_required is True
    assert invariants.admin_must_read_persisted is True


def test_public_create_route_takes_no_caller_authorization():
    """submitContact (the shared adapter behind functions/api/contact.js and
    server/api/contact.post.ts) has no `authorization` parameter at all -- an
    anonymous visitor can create a submission, matching "public create"."""
    shared = contact_adapter_files("html")["functions/_lib/p2hs-contact.mjs"]
    params = _signature(shared, "submitContact")
    assert "authorization" not in params.lower()


def test_staff_read_route_requires_and_forwards_a_bearer_token():
    """listContactInbox (the shared adapter behind functions/api/contact/inbox.js
    and server/api/contact/inbox.get.ts) requires `authorization` and the wrapper
    routes both forward the caller's real header, never a service token standing
    in for the caller."""
    files = contact_adapter_files("nuxt_app")
    shared = files["functions/_lib/p2hs-contact.mjs"]
    params = _signature(shared, "listContactInbox")
    assert "authorization" in params.lower()

    # Pages Functions wrappers read the raw Fetch API; Nuxt/Nitro wrappers use h3's
    # getHeader -- both are legitimate ways to forward the caller's own header.
    forwards_authorization = re.compile(
        r"""headers\.get\(\s*["']authorization["']\s*\)|getHeader\(\s*event\s*,\s*["']authorization["']\s*\)""",
        re.I,
    )
    pages_wrapper = files["functions/api/contact/inbox.js"]
    nuxt_wrapper = files["server/api/contact/inbox.get.ts"]
    for wrapper in (pages_wrapper, nuxt_wrapper):
        assert forwards_authorization.search(wrapper), wrapper
        assert "cloudServiceToken" not in wrapper, "must forward the caller's token, not the service token"


def test_public_create_route_never_forwards_a_caller_token_either():
    """The create wrapper must not read/forward an incoming Authorization header --
    that would silently and pointlessly gate a form that's supposed to be public."""
    files = contact_adapter_files("html")
    create_wrapper = files["functions/api/contact.js"]
    assert not re.search(r"headers\.get\(\s*[\"']authorization[\"']\s*\)", create_wrapper, re.I)
