"""Phase 10G — generated quote vertical runtime proof."""

from __future__ import annotations

import json
import tempfile
from pathlib import Path

import pytest

from src.domain.app_blocks.execution import assert_install_plan_installable
from src.domain.app_blocks.hosts import host_map_payload
from src.domain.app_blocks.quote_vertical import (
    BLOCK_OWNS_DECLARED_EXECUTION_CONTRACTS_ONLY,
    CROSS_BLOCK_EXECUTION_BINDING_DUPLICATION,
    QUOTE_BINDING_OWNERS,
    compile_quote_vertical_plan,
)
from src.domain.app_blocks.quote_vertical_runtime import (
    HOST_MOUNTS,
    QuoteVerticalRuntime,
    RUNTIME_DEPENDENCY_STATUSES,
    WorkflowTransitionRejected,
    assert_generated_quote_artifact,
    classify_runtime_dependencies,
    materialize_quote_vertical_product,
    quote_plan_without_email,
)
from src.domain.app_blocks.registry import load_default_registry
from src.domain.codegen.backend_guard import validate_backend_repo
from src.domain.codegen.prompt_wrapper import _APP_BLOCK_CONTRACT
from src.domain.feature_packs.events import COMPOSITION_ONLY_EVENT_IDS


def _materialize() -> tuple[Path, object]:
    raw = tempfile.TemporaryDirectory()
    root = Path(raw.name)
    plan = materialize_quote_vertical_product(root)
    return root, plan, raw


def test_10g_email_unconfigured_build_succeeds_and_stays_configuration_required():
    root, plan, _hold = _materialize()
    assert_install_plan_installable(plan)
    assert "email.send" in plan.runtime_dependencies
    assert all(gap.severity != "build_blocking" for gap in plan.gaps)
    report = assert_generated_quote_artifact(root)
    assert report["email_status"] == "configuration_required"
    settings = (root / "pages" / "admin" / "settings.vue").read_text(encoding="utf-8")
    assert "Setup required" in settings
    assert "Email notifications" in settings or "email.label" in settings
    deps = json.loads((root / "p2hs" / "runtime-dependencies.json").read_text(encoding="utf-8"))
    email = deps["email.send"]
    assert email["status"] == "configuration_required"
    assert email["available"] is False
    assert email["setup_required"] is True
    assert set(RUNTIME_DEPENDENCY_STATUSES) == {
        "ready",
        "configuration_required",
        "degraded",
        "disabled",
        "unsupported",
    }


def test_10g_generated_routes_mount_hosts_and_platform_calls():
    root, plan, _hold = _materialize()
    validate_backend_repo(str(root))
    report = assert_generated_quote_artifact(root)
    public = (root / "pages" / "request-quote.vue").read_text(encoding="utf-8")
    form = (root / "components" / "starter" / "blocks" / "QuotePublicForm.vue").read_text(
        encoding="utf-8"
    )
    listing = (root / "components" / "starter" / "RecordTable.vue").read_text(encoding="utf-8")
    detail = (root / "components" / "starter" / "RecordDetail.vue").read_text(encoding="utf-8")
    assert "QuotePublicForm" in public
    assert "submitGeneratedForm" in form
    assert "formKey: 'quote_request'" in form
    assert "listRecords('quote_request')" in listing
    assert "getRecord('quote_request'" in detail
    assert "patchRecord('quote_request'" in detail
    quote = next(block for block in plan.blocks if block.id == "forms.quote_request")
    assert "Request a quote" in form
    assert quote.slots["heading"] == "Request a quote"
    table = next(block for block in plan.blocks if block.id == "admin.record_table")
    assert table.slots.get("empty_state") in listing
    catalog = host_map_payload()
    by_key = {(item["block"], item["slot"]): item for item in catalog["hosts"]}
    for (block, slot), rel in HOST_MOUNTS.items():
        assert report["host_mounts"][f"{block}#{slot}"] == rel
        assert by_key[(block, slot)]["component_contract"]
        assert by_key[(block, slot)]["implementation"] is None
    registry = load_default_registry()
    for block_id, slot_id in HOST_MOUNTS:
        manifest = registry.require(block_id)
        slot = next(item for item in manifest.slots if item.id == slot_id)
        assert slot.constraints.editable is False


def test_10g_generated_artifact_has_no_private_execution_substitutes():
    root, _plan, _hold = _materialize()
    blob = "\n".join(
        path.read_text(encoding="utf-8")
        for path in root.rglob("*")
        if path.is_file() and path.suffix in {".vue", ".js", ".ts", ".json"}
    )
    for marker in (
        "new PrismaClient",
        "better-sqlite3",
        "sqlite3",
        "supabase",
        "new Resend",
        "ALLOWED_TRANSITIONS",
        "/api/quote",
        "/api/quotes",
        "emitDomainEvent",
        "forms.quote_request.submitted",
    ):
        assert marker not in blob
    assert BLOCK_OWNS_DECLARED_EXECUTION_CONTRACTS_ONLY is True
    assert CROSS_BLOCK_EXECUTION_BINDING_DUPLICATION is False
    plan = compile_quote_vertical_plan()
    by_id = {block.id: set(block.protected_bindings) for block in plan.blocks}
    assert "query" not in by_id["forms.quote_request"]
    assert "persistence" not in by_id["admin.record_table"]
    assert QUOTE_BINDING_OWNERS["admin.record_detail"] <= by_id["admin.record_detail"]


def test_10g_runtime_submit_list_detail_and_legal_workflow():
    root, _plan, _hold = _materialize()
    assert_generated_quote_artifact(root)
    kernel = QuoteVerticalRuntime()
    created = kernel.submit_generated_form(
        form_key="quote_request",
        values={"name": "Ada", "email": "ada@example.com", "details": "Roof leak"},
    )
    assert created.data["status"] == "new"
    rows = kernel.list_records("quote_request")
    assert len(rows) == 1
    assert rows[0]["email"] == "ada@example.com"
    loaded = kernel.get_record("quote_request", created.id)
    assert loaded["status"] == "new"
    reviewing = kernel.patch_record("quote_request", created.id, {"status": "reviewing"})
    quoted = kernel.patch_record("quote_request", created.id, {"status": "quoted"})
    won = kernel.patch_record("quote_request", created.id, {"status": "won"})
    assert reviewing["status"] == "reviewing"
    assert quoted["status"] == "quoted"
    assert won["status"] == "won"


def test_10g_runtime_rejects_illegal_transition_without_local_authority():
    root, _plan, _hold = _materialize()
    detail = (root / "components" / "starter" / "RecordDetail.vue").read_text(encoding="utf-8")
    assert "ALLOWED_TRANSITIONS" not in detail
    assert "patchRecord" in detail
    kernel = QuoteVerticalRuntime()
    created = kernel.submit_generated_form(
        form_key="quote_request",
        values={"name": "Ada", "email": "ada@example.com"},
    )
    with pytest.raises(WorkflowTransitionRejected) as error:
        kernel.patch_record("quote_request", created.id, {"status": "won"})
    assert error.value.status_code == 409
    assert error.value.from_state == "new"
    assert error.value.to_state == "won"
    assert kernel.get_record("quote_request", created.id)["status"] == "new"
    with pytest.raises(RuntimeError, match="composition-only"):
        kernel.emit_quote_submitted_event()
    assert "forms.quote_request.submitted" in COMPOSITION_ONLY_EVENT_IDS
    assert "ready`, `configuration_required`" in _APP_BLOCK_CONTRACT or (
        "ready" in _APP_BLOCK_CONTRACT and "configuration_required" in _APP_BLOCK_CONTRACT
    )


def test_10g_does_not_infer_email_provider_or_quote_event():
    root, plan, _hold = _materialize()
    deps = classify_runtime_dependencies(plan)
    assert deps["email.send"]["status"] != "ready"
    client = (root / "lib" / "p2hs-app.js").read_text(encoding="utf-8")
    assert "from 'resend'" not in client
    assert "nodemailer" not in client
    with pytest.raises(ValueError, match="Cloud persistence contract failed"):
        (root / "server" / "api" / "quotes.post.ts").parent.mkdir(parents=True)
        (root / "server" / "api" / "quotes.post.ts").write_text(
            "import { PrismaClient } from '@prisma/client'\nexport default new PrismaClient()\n",
            encoding="utf-8",
        )
        validate_backend_repo(str(root))
