"""7O Forms Codegen exposure. 7B–7N runtime truth stays frozen. Binding is 7P."""
from __future__ import annotations

import json
from pathlib import Path

from src.domain.codegen.forms_adapter import forms_adapter_files
from src.domain.codegen.forms_codegen import (
    CLIENT_SAFE_FIELD_KEYS,
    FORMS_CODEGEN_PHASE_7O,
    FORMS_CODEGEN_POLICY,
    GENERIC_FORMS_LEAK_TOKENS,
    INSTALLED_FORMS_SUBMIT_ROUTE,
    classify_form_intent,
    example_canonical_form_submit,
    generic_forms_snippet_leaks,
    project_client_form_config,
    select_forms_generation,
)
from src.domain.codegen.platform_backend import build_platform_backend_capabilities
from src.domain.codegen.prompt_wrapper import _P2HS_CLOUD_CONTRACT, _app_recipes
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    FORMS_FAMILY_PLAN,
    FORMS_HYPOTHESIZED_VERBS_NOT_FROZEN,
    INVOKE_CAPABILITIES,
)
from src.domain.connectors.public_gateway import PHASE_7_STATUS, PUBLIC_INVOCABLE_CAPABILITIES
from src.domain.forms.actions import FormPostSubmitAction, FormPostSubmitPlan
from src.domain.forms.canonical import (
    FormDefinition,
    FormField,
    FormFieldOption,
    contact_block_compatible_definition,
)
from src.domain.forms.conditions import (
    FieldConditionalRule,
    FormCondition,
    FormConditionSet,
)
from src.domain.forms.public import (
    InMemoryFormRuntimeStore,
    ResolvedFormRuntime,
    SilentCapabilityInvoker,
    submit_form,
)
from src.domain.forms.steps import FormStep, FormStepPlan


def test_7o_closes_codegen_exposure_without_binding_or_capability() -> None:
    assert PHASE_7_STATUS == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["phase_7_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == (
        "9_app_block_modernization"
    )
    assert CAPABILITY_CONVERSION_PATTERN["opened_families"]["forms.*"] == (
        "composition_integration"
    )
    assert FORMS_FAMILY_PLAN["status"] == "complete"
    assert FORMS_FAMILY_PLAN["codegen_exposure_frozen"] is True
    assert FORMS_FAMILY_PLAN["composition_integration_frozen"] is True
    assert FORMS_FAMILY_PLAN["public_runtime_frozen"] is True
    assert FORMS_FAMILY_PLAN["slices"][13] == "7n_public_bff_runtime_truth"
    assert FORMS_FAMILY_PLAN["slices"][14] == "7o_codegen_exposure"
    assert FORMS_FAMILY_PLAN["next_slice"] == "9_app_block_modernization"
    assert FORMS_CODEGEN_PHASE_7O["status"] == "frozen"
    assert FORMS_CODEGEN_PHASE_7O["runtime_binding"] == "7p"
    assert FORMS_CODEGEN_PHASE_7O["form_submit_capability"] is False
    assert FORMS_CODEGEN_PHASE_7O["legacy_contact_unchanged"] is True
    assert FORMS_CODEGEN_PHASE_7O["app_blocks_unchanged"] is True
    assert "form.submit" not in INVOKE_CAPABILITIES
    assert "form.submit" in FORMS_HYPOTHESIZED_VERBS_NOT_FROZEN
    assert "form.submit" not in PUBLIC_INVOCABLE_CAPABILITIES


def test_intent_classification() -> None:
    assert classify_form_intent("build a contact form") == "public_submission_form"
    assert classify_form_intent("quote request") == "public_submission_form"
    assert classify_form_intent("multi-step intake form") == "public_submission_form"
    assert classify_form_intent("keep forms.contact as today") == (
        "public_submission_form"
    )
    assert classify_form_intent("login form") == "auth"
    assert classify_form_intent("edit record") == "crud"
    assert classify_form_intent("search form") == "search"
    assert classify_form_intent("checkout payment form") == "checkout"
    assert classify_form_intent("embed HubSpot form") == "provider_escape"
    generic = select_forms_generation("build an intake form")
    assert generic.runtime == "canonical_forms"
    assert generic.route == INSTALLED_FORMS_SUBMIT_ROUTE
    contact = select_forms_generation("forms.contact contact-capture")
    assert contact.runtime == "canonical_forms"
    assert contact.route == INSTALLED_FORMS_SUBMIT_ROUTE
    legacy = select_forms_generation("keep /api/contact for old apps")
    assert legacy.runtime == "legacy_contact_adapter"
    assert legacy.route == "POST /api/contact"
    crud = select_forms_generation("admin editor for inventory")
    assert crud.runtime == "existing_product"


def test_client_projection_strips_server_trust_and_is_provider_neutral() -> None:
    definition = FormDefinition(
        key="intake",
        fields=[
            FormField(key="has_company", type="checkbox", required=False, label="Company?"),
            FormField(key="company_name", type="text", required=False, label="Company"),
            FormField(key="email", type="email", required=True, label="Email"),
            FormField(
                key="contact_method",
                type="select",
                required=False,
                options=[
                    FormFieldOption(value="email", label="Email"),
                    FormFieldOption(value="phone", label="Phone"),
                ],
            ),
            FormField(key="phone", type="phone", required=False),
            FormField(key="attachment", type="file", required=False),
        ],
    )
    conditions = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="company_name",
                effect="show_when",
                condition=FormCondition(field_key="has_company", operator="equals", value=True),
            ),
            FieldConditionalRule(
                target_field="phone",
                effect="require_when",
                condition=FormCondition(
                    field_key="contact_method", operator="equals", value="phone"
                ),
            ),
        ),
    )
    steps = FormStepPlan(
        form_key="intake",
        steps=(
            FormStep(key="basics", field_keys=("has_company", "company_name", "email")),
            FormStep(key="details", field_keys=("contact_method", "phone", "attachment")),
        ),
    )
    hubspot = project_client_form_config(definition, conditions=conditions, step_plan=steps)
    salesforce = project_client_form_config(definition, conditions=conditions, step_plan=steps)
    assert hubspot == salesforce
    dumped = str(hubspot)
    assert "actions" not in hubspot
    assert "run_when" not in dumped
    for field in hubspot["fields"]:
        assert set(field) <= set(CLIENT_SAFE_FIELD_KEYS)
    assert "persist_first" not in dumped
    assert "provider_hint" not in dumped
    assert hubspot["submit"]["path"] == "/api/forms/intake/submissions"
    assert hubspot["show_when"][0]["target_field"] == "company_name"
    assert hubspot["require_when"][0]["target_field"] == "phone"
    assert [step["key"] for step in hubspot["steps"]] == ["basics", "details"]
    plan = FormPostSubmitPlan(
        actions=(
            FormPostSubmitAction(
                key="sync_crm",
                action_type="crm.contact.upsert",
                mapping={"email": "email"},
            ),
        )
    )
    assert plan.actions[0].action_type == "crm.contact.upsert"
    assert "crm.contact.upsert" not in dumped


def test_prompts_and_recipes_expose_canonical_forms_without_rewriting_contact() -> None:
    recipes = _app_recipes()
    assert "submitGeneratedForm" in recipes
    assert "POST /api/forms/" in recipes
    assert "submitContact" in recipes
    assert "POST /api/contact" in recipes
    assert FORMS_CODEGEN_POLICY.strip() in _P2HS_CLOUD_CONTRACT

    class _Manifest:
        def model_dump(self, mode="json"):
            return {"credentials": {}, "project": {}, "backend": {}}

    caps = build_platform_backend_capabilities(_Manifest())
    assert any("canonical Forms" in rule for rule in caps["rules"])
    recipe_json = Path("src/domain/codegen/runtime/app-recipe.json").read_text(
        encoding="utf-8"
    )
    recipes_doc = json.loads(recipe_json)
    assert recipes_doc["recipes"]["submit_form"]["route"].startswith("POST /api/forms/")
    assert recipes_doc["recipes"]["submit_form_legacy"]["status"] == "compatibility_only"
    assert "submit_canonical_form" in recipe_json
    assert '"route": "POST /api/contact"' in recipe_json
    client = Path("src/domain/codegen/runtime/p2hs-app-client.js").read_text(
        encoding="utf-8"
    )
    assert "submitGeneratedForm" in client
    assert "/api/forms/" in client
    assert "P2HS_BACKEND_URL" not in client
    contact = Path("src/domain/codegen/runtime/p2hs-contact.mjs").read_text(encoding="utf-8")
    assert "submitContact" in client
    assert "CLOUD_SERVICE_TOKEN" in contact or "cloudServiceToken" in contact


def test_installed_adapter_is_host_relative_and_does_not_register_runtime() -> None:
    files = forms_adapter_files("nuxt_app")
    runtime = files["functions/_lib/p2hs-forms-runtime.mjs"]
    submit = files["functions/_lib/p2hs-forms-submit.mjs"]
    pages = files["functions/api/forms/[formKey]/submissions.js"]
    nuxt = files["server/api/forms/[formKey]/submissions.post.ts"]
    for source in (runtime, submit, pages, nuxt):
        assert generic_forms_snippet_leaks(source) == ()
        assert "FormRuntimeStore" not in source
        assert "beapipie" not in source.lower()
        assert "api.hubapi.com" not in source
    assert "/api/forms/${encodeURIComponent(formKey)}/submissions" in runtime
    assert "P2HS_CORE_URL" in submit
    assert "NUXT_PUBLIC_P2HS_CORE_PUBLIC_URL" not in submit
    snippet = str(example_canonical_form_submit("quote_request"))
    assert "/api/forms/quote_request/submissions" in snippet
    assert "project_id" not in snippet


def test_legacy_submit_form_entry_and_contact_block_untouched() -> None:
    legacy = Path("src/domain/codegen/runtime/p2hs-forms.mjs").read_text(encoding="utf-8")
    assert "export async function submitFormEntry" in legacy
    assert "/api/forms/" not in legacy
    definition = contact_block_compatible_definition()
    assert definition.key == "contact"
    manifest = Path("src/domain/app_blocks/manifests/forms.contact.v1.yaml")
    assert manifest.is_file()
    yaml_text = manifest.read_text(encoding="utf-8")
    assert "forms.contact" in yaml_text
    assert "submitGeneratedForm" not in yaml_text


def test_unbound_runtime_is_form_unavailable_not_a_codegen_bug() -> None:
    empty = InMemoryFormRuntimeStore()
    result = submit_form(
        project_id="prj_unbound",
        form_key="intake",
        values={"email": "ada@example.com"},
        client_identity="127.0.0.1",
        runtimes=empty,
        invoker=SilentCapabilityInvoker(),
    )
    assert result.body["error"] == "form_unavailable"
    store = InMemoryFormRuntimeStore()
    store.put(
        "prj_fixture",
        ResolvedFormRuntime(definition=contact_block_compatible_definition()),
    )
    accepted = submit_form(
        project_id="prj_fixture",
        form_key="contact",
        values={
            "name": "Ada",
            "email": "ada@example.com",
            "message": "Hello",
        },
        client_identity="127.0.0.1",
        runtimes=store,
        invoker=SilentCapabilityInvoker(),
    )
    assert accepted.body["ok"] is True
    assert accepted.body["status"] == "accepted"
    assert accepted.body["submission_id"].startswith("fsb_")


def test_generated_helpers_must_not_leak_integration_verbs() -> None:
    root = Path("src/domain/codegen/runtime")
    generated = "\n".join(
        path.read_text(encoding="utf-8")
        for path in (
            root / "p2hs-forms-runtime.mjs",
            root / "p2hs-forms-submit.mjs",
            root / "p2hs-app-client.js",
            root / "forms-submit-pages-fn.js",
            root / "forms-submit-route.ts",
        )
    )
    for token in GENERIC_FORMS_LEAK_TOKENS:
        assert token.lower() not in generated.lower(), token
    assert "await upsertContact" not in generated
    assert "await sendEmail" not in generated
