import json
import tempfile
from pathlib import Path

from src.domain.codegen.app_sdk import (
    RECIPE_PATH,
    app_sdk_files,
    ensure_contact_capture_manifest,
    staff_shell_files,
)
from src.domain.codegen.platform_backend import compact_platform_backend_for_prompt
from src.domain.codegen.port_adapter import LOCK_PATH, catalog_adapter_files, install_catalog_adapters
from src.domain.codegen.prompt_wrapper import build_system_prompt


def test_app_sdk_is_locked_for_each_pages_type():
    html = catalog_adapter_files("html")
    assert RECIPE_PATH in html
    assert "js/p2hs-app.js" in html
    assert "submitContact" in html["js/p2hs-app.js"]
    assert "/api/jobs/email.send" in html["js/p2hs-app.js"]
    manifest = json.loads(html["p2hs/managed-runtime.json"])
    assert manifest["base_runtime"] == {
        "contract": "p2hs-generated-app-base",
        "version": "2",
    }
    assert "p2hs-generated-app-base-v2" in manifest["migration_lineage"]
    assert manifest["components"]["auth_session"]["ownership"] == "p2hs_managed"
    assert manifest["components"]["auth_session"]["paths"] == ["js/p2hs-app.js"]
    assert manifest["components"]["auth_session"]["expected_fingerprint"].startswith("sha256:")
    lock = json.loads(html[LOCK_PATH])
    assert RECIPE_PATH in lock["files"]

    react = catalog_adapter_files("react_app")
    assert "src/lib/p2hs-app.js" in react
    assert "js/p2hs-app.js" not in react

    nuxt = catalog_adapter_files("nuxt_app")
    assert "lib/p2hs-app.js" in nuxt
    assert "composables/useP2hs.ts" in nuxt
    assert "../lib/p2hs-app.js" in nuxt["composables/useP2hs.ts"]
    assert app_sdk_files("shopify_app") == {}


def test_install_seeds_staff_shell_without_forcing_contact_pack():
    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        install_catalog_adapters(raw, "nuxt_app")
        assert not (root / "p2hs/feature-packs.json").exists()
        assert (root / "pages/admin/index.vue").is_file()
        assert "listInbox" in (root / "pages/admin/index.vue").read_text(encoding="utf-8")
        assert (root / RECIPE_PATH).is_file()
        (root / "pages/admin/index.vue").write_text("<!-- owner styled -->\n", encoding="utf-8")
        install_catalog_adapters(raw, "nuxt_app")
        assert (root / "pages/admin/index.vue").read_text(encoding="utf-8") == "<!-- owner styled -->\n"


def test_install_declares_plan_required_packs():
    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        plan_path = root / "p2hs" / "app-blocks-plan.json"
        plan_path.parent.mkdir(parents=True)
        plan_path.write_text(
            json.dumps({
                "adoption": "authoritative",
                "required_feature_packs": ["contact-capture"],
            }),
            encoding="utf-8",
        )
        install_catalog_adapters(raw, "nuxt_app")
        packs = json.loads((root / "p2hs/feature-packs.json").read_text(encoding="utf-8"))
        assert packs["install"][0]["pack_slug"] == "contact-capture"


def test_staff_shell_skipped_when_custom_admin_exists():
    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        (root / "pages/be-admin").mkdir(parents=True)
        (root / "pages/be-admin/index.vue").write_text("<template>custom</template>\n")
        assert staff_shell_files("nuxt_app", raw) == {}


def test_contact_capture_manifest_merges_without_wiping():
    with tempfile.TemporaryDirectory() as raw:
        path = Path(raw) / "p2hs/feature-packs.json"
        path.parent.mkdir()
        path.write_text(
            json.dumps({
                "version": 1,
                "install": [{"pack_slug": "appointment-booking", "config": {"x": 1}}],
            }),
            encoding="utf-8",
        )
        ensure_contact_capture_manifest(raw)
        data = json.loads(path.read_text(encoding="utf-8"))
        slugs = [row["pack_slug"] for row in data["install"]]
        assert slugs == ["appointment-booking", "contact-capture"]
        assert data["install"][0]["config"] == {"x": 1}


def test_contact_capture_manifest_fills_notify_email_without_wiping_other_packs():
    with tempfile.TemporaryDirectory() as raw:
        path = Path(raw) / "p2hs/feature-packs.json"
        path.parent.mkdir()
        path.write_text(
            json.dumps({
                "version": 1,
                "install": [{"pack_slug": "contact-capture", "config": {}}],
            }),
            encoding="utf-8",
        )
        ensure_contact_capture_manifest(raw, notify_to_email="owner@wash.example")
        data = json.loads(path.read_text(encoding="utf-8"))
        assert data["install"][0]["config"]["notify_to_email"] == "owner@wash.example"


def test_prompt_leads_with_app_recipes_and_compacts_schemas():
    prompt = build_system_prompt("nuxt_app", "")
    assert "App recipes" in prompt
    assert "submitContact" in prompt
    assert "p2hs/app-recipe.json" in prompt
    assert prompt.index("App recipes") < prompt.index("PlatformBackendCapabilities")


def test_prompt_requires_backend_quality_pass_without_invented_modules():
    prompt = build_system_prompt("nuxt_app", "")
    assert "Backend Quality Pass" in prompt
    assert "Never add fake analytics" in prompt
    assert "local user stores" in prompt

    bloated = {
        "contract_name": "PlatformBackendCapabilities",
        "api_surface": {
            "jobs": {
                "email_send": {
                    "port_id": "jobs.email_send",
                    "method": "POST",
                    "path": "/api/jobs/email.send",
                    "auth": "staff",
                    "schema": {"request_body": {"properties": {"n": i for i in range(50)}}},
                }
            }
        },
        "rules": ["keep", "drop-me-if-long"] + [f"pack-rule-{i}" for i in range(20)],
        "database": {
            "schema_status": "ready",
            "entities": [{"key": "contact_submission", "fields": [{"key": "email"}]}],
        },
    }
    compact = compact_platform_backend_for_prompt(bloated)
    assert "schema" not in compact["api_surface"]["jobs"]["email_send"]
    assert compact["api_surface"]["jobs"]["email_send"]["path"] == "/api/jobs/email.send"
    assert compact["database"]["entities"][0]["fields"] == ["email"]
    assert len(compact["rules"]) == 14
    section = build_system_prompt("html", "", platform_backend=bloated)
    assert "request_body" not in section
    assert "/api/jobs/email.send" in section
