"""Architecture Lane Contract: admit contract over live data.entity.

Freeze deliberately lifted for the Native Capability Baseline (explicit user
decision, not harvest ranking -- workforce/property/lab stay guarded). No new
kernel, no e-signature admission, no document-content ownership (that stays
with documents/files.attachments).
"""

from pathlib import Path

import pytest
import yaml
from src.domain.app_blocks.canonical import CANONICAL_BLOCK_IDS, feature_pack_only_aliases
from src.domain.app_blocks.catalogs import FEATURE_PACK_ALIASES, default_known_packs
from src.domain.app_blocks.execution import assert_install_plan_installable
from src.domain.app_blocks.generated_product_conformance_12h import (
    KernelDeniedError,
    PlatformKernel,
)
from src.domain.app_blocks.planner import ProductIntent, select_capabilities
from src.domain.app_blocks.registry import load_default_registry
from src.domain.app_blocks.vertical_recipes import match_vertical_recipe
from src.domain.starter_library.catalog import known_contract_ids

from tests.test_phase11_pack_migration_materialization import _captured_composition

ROOT = Path(__file__).resolve().parents[1]
RECEIPT = ROOT / "src/domain/app_blocks/recipes/contract_freeze.receipt.txt"
AUDIT = ROOT / "docs/audits/ARCHITECTURE_LANE_CONTRACT.md"
REGISTRY = ROOT / "src/domain/app_blocks/platform_coverage_registry.v1.yaml"
GATED = (
    "payments.checkout",
    "membership.portal",
)
STARTER_SLOTS = {
    "list": "record.table",
    "detail": "record.detail",
    "create": "record.create",
    "edit": "record.edit",
    "empty": "state.empty",
}


def contract_composition():
    return _captured_composition(
        "alembic/versions/156_contract_management_pack.py", "contract-management"
    )


def _ids(intent: ProductIntent) -> set[str]:
    return {block_id for _cap, block_id, _reason in select_capabilities(intent)}


def test_contract_runtime_is_canonical_without_new_kernel():
    registry = load_default_registry()
    block = registry.require("contract.contract")
    canonical = registry.canonical.require("contract.contract")
    assert block.status == "implemented"
    assert block.lifecycle == "stable"
    assert "contract.contract" in CANONICAL_BLOCK_IDS
    assert "contract.contract" not in FEATURE_PACK_ALIASES
    assert "contract.contract" not in feature_pack_only_aliases()
    assert canonical.installation.feature_packs == ("contract-management",)
    primitives = {dep.id for dep in canonical.requires if dep.kind == "primitive"}
    assert primitives == {"data.entity"}
    assert "contract-management" in default_known_packs()
    composition = contract_composition()
    entity = composition["entities"][0]
    assert entity["entity_key"] == "contract"
    keys = {field["key"] for field in entity["schema"]["fields"]}
    assert keys == {
        "reference",
        "counterparty_name",
        "counterparty_email",
        "start_date",
        "end_date",
        "renewal_date",
        "notice_date",
        "notes",
        "status",
    }
    status = next(field for field in entity["schema"]["fields"] if field["key"] == "status")
    assert status["options"] == ["draft", "active", "terminated", "renewed"]
    assert "signature_status" not in keys
    assert "esign_envelope_id" not in keys
    assert "document_body" not in keys


def test_contract_install_plan_does_not_bind_esign(monkeypatch):
    from src.domain.app_blocks import compiler

    registry = load_default_registry()
    monkeypatch.setattr(
        compiler,
        "select_capabilities",
        lambda _intent: [("contract_contract", "contract.contract", "Selected.")],
    )
    plan = compiler.compile_install_plan(None, registry=registry)
    assert_install_plan_installable(plan)
    assert "contract-management" in plan.required_feature_packs
    assert "payment-checkout" not in plan.required_feature_packs
    assert "data.entity" in plan.required_primitives


def test_contract_does_not_imply_esign_or_documents():
    ids = _ids(
        ProductIntent(
            purpose="Staff need contract management. No e-signature, no documents.",
            source_prompt="Staff need contract management. No e-signature, no documents.",
            staff_review=True,
        )
    )
    assert "contract.contract" in ids
    assert "documents" not in ids
    assert not (ids & set(GATED))


def test_contract_and_crm_compose_without_merging_stores():
    prompt = "Staff manage contracts with counterparties tracked as customer records."
    ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
    assert "contract.contract" in ids


def test_false_positives_do_not_select_contract():
    for purpose in (
        "customers pay us later",
        "pricing page",
        "Staff manage a product catalog",
        "employment contract onboarding paperwork",
    ):
        ids = _ids(ProductIntent(purpose=purpose, source_prompt=purpose, staff_review=True))
        assert "contract.contract" not in ids, purpose


def test_negative_intent_skips_contract():
    for prompt in (
        "Client records for the firm. Do not add contract management.",
        "Staff CRM. No contract records.",
    ):
        ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
        assert "contract.contract" not in ids, prompt


def test_positive_intent_selects_contract():
    for prompt in (
        "Staff need to track contracts and renewal dates.",
        "Build contract management for vendor agreements.",
        "Track contract lifecycle from draft to renewal.",
    ):
        ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
        assert "contract.contract" in ids, prompt
        assert not (ids & set(GATED)), prompt


def test_13a_do_not_create_orders_still_misses_contract():
    prompt = (
        "Our sales office maintains catalog items in a shared list. "
        "Employees should sign in, add items and correct descriptions. Do not create orders."
    )
    assert match_vertical_recipe(prompt) is None
    ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
    assert "catalog.product" in ids
    assert "contract.contract" not in ids


def test_contract_reuses_record_starter_contracts():
    registry = load_default_registry()
    block = registry.require("contract.contract")
    contracts = {
        slot.id: slot.component_contract
        for slot in block.slots
        if slot.component_contract
    }
    assert STARTER_SLOTS.items() <= contracts.items()
    assert "contract.list" not in known_contract_ids()


def test_contract_runtime_crud_is_staff_managed_records():
    kernel = PlatformKernel(namespace="contract-freeze")
    kernel.as_anonymous()
    with pytest.raises(KernelDeniedError):
        kernel.create_record("contract", {"reference": "C-1"})
    kernel.as_staff()
    created = kernel.create_record(
        "contract",
        {
            "reference": "C-1048",
            "counterparty_name": "Acme Corp",
            "counterparty_email": "legal@acme.example",
            "start_date": "2026-01-01",
            "end_date": "2026-12-31",
            "status": "active",
        },
    )
    listed = kernel.list_records("contract")
    assert listed[0]["id"] == created["id"]
    kernel.patch_record("contract", created["id"], {"status": "renewed"})
    read = kernel.get_record("contract", created["id"])
    assert read["status"] == "renewed"
    assert read["reference"] == "C-1048"
    other = PlatformKernel(namespace="contract-other")
    other.as_staff()
    assert other.list_records("contract") == []


def test_materialized_contract_hosts_use_records_not_esign():
    import json

    from src.domain.app_blocks.hosts import merge_host_map

    for framework in ("html", "nuxt_app", "react_app"):
        root = ROOT / "boilerplates" / framework
        hosts = merge_host_map(json.loads((root / "p2hs/app-block-hosts.json").read_text()))
        rows = {h["slot"]: h for h in hosts["hosts"] if h["block"] == "contract.contract"}
        assert {"list", "detail", "create", "edit", "empty"} <= set(rows)
        for slot in ("list", "detail", "create", "edit"):
            path = rows[slot]["implementation"].partition("#")[0]
            source = (root / path).read_text(encoding="utf-8")
            assert "contract" in source
            assert "docusign" not in source.lower()
            assert "hellosign" not in source.lower()


def test_contract_freeze_receipts_and_coverage_next_family():
    receipt = RECEIPT.read_text(encoding="utf-8")
    audit = AUDIT.read_text(encoding="utf-8")
    for required in (
        "contract_admitted=yes",
        "canonical_app_block=contract.contract",
        "canonical_feature_pack=contract-management",
        "contract_without_esign=yes",
        "family_frozen=yes",
    ):
        assert required in receipt, required
    assert "contract_freeze=yes" in audit
    registry = yaml.safe_load(REGISTRY.read_text(encoding="utf-8"))
    by_id = {row["id"]: row for row in registry["capabilities"]}
    assert by_id["contract.contract"]["status"] == "frozen"
    assert by_id["contract"]["status"] == "frozen"
    assert by_id["contract-management"]["status"] == "frozen"


def test_contract_production_smoke_script():
    from scripts.architecture_lane_contract_smoke import run_smoke

    payload = run_smoke()
    assert payload["pass"] is True, payload["failures"]
    assert payload["on_disk_contract_recipes"] == []
