"""Phase 12H — exhaustive generated-product conformance certification."""

from __future__ import annotations

import json
import tempfile
from pathlib import Path

import pytest
from src.domain.app_blocks.canonical import CANONICAL_BLOCK_IDS
from src.domain.app_blocks.generated_product_conformance_12h import (
    ARCHETYPES,
    STARTERS,
    BookingConflictError,
    KernelDeniedError,
    PlatformKernel,
    certification_fixture,
    certify_matrix,
    compile_cert_plan,
    optional_requires_not_installed,
    planned_surfaces,
    write_matrix_artifact,
)
from src.domain.app_blocks.registry import load_default_registry
from src.domain.starter_library.catalog import known_contract_ids

ROOT = Path(__file__).resolve().parents[1]
MATRIX = ROOT / "docs" / "audits" / "fixtures" / "12h_certification_matrix.json"
STARTER_IDS = frozenset(known_contract_ids())


@pytest.fixture(scope="module")
def matrix():
    # Generated Windows files can remain briefly open after the matrix worker
    # exits; cleanup failure must not invalidate an otherwise completed proof.
    raw = tempfile.TemporaryDirectory(prefix="p2hs-12h-", ignore_cleanup_errors=True)
    try:
        cells = certify_matrix(Path(raw.name))
        write_matrix_artifact(cells, MATRIX)
        yield cells
    finally:
        raw.cleanup()


def test_12h_does_not_mint_architecture():
    # GR-05 (Phase 13, explicitly authorized) admitted support.ticket over
    # the pre-existing support-inbox Feature Pack (19 -> 20); GR-06 admitted
    # workflow.approval over the pre-existing approval-workflow Feature Pack
    # (20 -> 21). See docs/audits/GR05_EXIT_REVIEW.md and
    # docs/audits/GR06_EXIT_REVIEW.md.
    assert known_contract_ids() == STARTER_IDS
    # Architecture Lane Membership admitted membership.member over membership-management (24 -> 25).
    # Capability Model Phase 4 admitted contract.contract (31 -> 32).
    # Capability Model Phase 5 admitted workforce.worker (32 -> 33).
    # Wave 5 admitted payments.checkout (33 -> 34).
    # Architecture Lane Visualization+Calculation admits visualization.chart and
    # calculation.calculator, and Organizations adds team/org_unit composition.
    assert len(CANONICAL_BLOCK_IDS) == 39
    assert load_default_registry().canonical.ids == CANONICAL_BLOCK_IDS


def test_12h_cert_fixtures_are_satisfiable_and_do_not_install_optionals():
    for archetype in ARCHETYPES:
        plan = compile_cert_plan(certification_fixture(archetype))
        assert plan.unsatisfiable is False
        assert plan.adoption == "authoritative"
        assert optional_requires_not_installed(plan)
        ids = {block.id for block in plan.blocks}
        if archetype == "A":
            assert {
                "crm.customer",
                "crm.lead",
                "crm.pipeline",
                "workflow.assignment",
                "task.management",
                "activity.timeline",
            } <= ids
        if archetype == "C":
            assert "forms.quote_request" in ids
            assert "forms.contact" not in ids
        if archetype == "F":
            assert "catalog.product" in ids


def test_12h_natural_intent_is_recorded_separately_from_conformance(matrix):
    # Was 15/18 (archetype A only had 3 fail_p2_matcher cells) at Phase 12I
    # closure; the post-B2 residual remediation pass (Phase 13) improved
    # general matcher precision/recall and closed those 3 cells as a side
    # effect -- see docs/audits/POST_B2_RESIDUAL_RECONCILIATION_RECEIPT.md.
    # This assertion tracks the *current* measurement, not a fixed ceiling.
    natural_pass = [cell for cell in matrix if cell.planner_intent_match == "pass"]
    cert_pass = [cell for cell in matrix if cell.result == "pass"]
    assert len(matrix) == 18
    assert len(cert_pass) == 18
    assert len(natural_pass) == 18


def test_12h_matrix_18_cells_pass(matrix):
    assert [(cell.archetype, cell.starter, cell.result) for cell in matrix] == [
        (archetype, starter, "pass")
        for archetype in ARCHETYPES
        for starter in STARTERS
    ]
    for cell in matrix:
        assert cell.plan_satisfiable is True
        assert cell.missing_must_surfaces == []
        assert cell.build_result == "pass"
        assert cell.auth_result == "pass"
        assert cell.primary_workflow_result == "pass"
        assert cell.runtime_authority_result == "pass"
        assert cell.persistence_result == "pass"
        assert cell.readback_result == "pass"
        assert cell.private_substitute_count == 0
        assert cell.unexpected_semantic_surfaces == []
        assert cell.planned_must_surfaces == cell.mounted_must_surfaces
        assert cell.mounted_must_surfaces == cell.reachable_must_surfaces
        assert cell.planned_must_surfaces > 0


def test_12h_cross_starter_semantics_match(matrix):
    by_arch = {}
    for cell in matrix:
        by_arch.setdefault(cell.archetype, []).append(cell)
    for archetype, cells in by_arch.items():
        blocks = [tuple(cell.planned_blocks) for cell in cells]
        assert len(set(blocks)) == 1
        must = {cell.planned_must_surfaces for cell in cells}
        assert len(must) == 1
        authorities = {tuple(row.runtime_authority for row in cell.ledger) for cell in cells}
        assert len(authorities) == 1, archetype


def test_12h_must_mount_uses_starter_hosts_not_catalog_only():
    plan = compile_cert_plan(certification_fixture("C"))
    nuxt = planned_surfaces(plan, "nuxt_app")
    quote = next(
        item
        for item in nuxt
        if item.block == "forms.quote_request" and item.slot == "public_form"
    )
    assert quote.implementation.endswith("QuotePublicForm.vue")
    assert quote.route == "/request-quote"


def test_12h_kernel_auth_and_booking_conflict():
    kernel = PlatformKernel("probe")
    created = kernel.submit_generated_form(form_key="quote_request", values={"name": "Ada"})
    with pytest.raises(KernelDeniedError):
        kernel.list_records("quote_request")
    kernel.as_staff()
    assert kernel.get_record("quote_request", created["id"])["status"] == "new"
    kernel.as_anonymous()
    with pytest.raises(KernelDeniedError):
        kernel.reserve(
            resource_key="r",
            starts_at="t",
            customer_name="Ada",
            customer_email="a@x.com",
        )
    kernel.as_staff()
    kernel.reserve(
        resource_key="r",
        starts_at="t",
        customer_name="Ada",
        customer_email="a@x.com",
    )
    with pytest.raises(BookingConflictError):
        kernel.reserve(
            resource_key="r",
            starts_at="t",
            customer_name="Bo",
            customer_email="b@x.com",
        )


def test_12h_matrix_artifact_written(matrix):
    assert MATRIX.is_file()
    payload = json.loads(MATRIX.read_text(encoding="utf-8"))
    assert payload["summary"]["certification_cells"] == 18
    assert payload["summary"]["cells_passed"] == 18
    assert payload["summary"]["cells_failed_p0"] == 0
    assert payload["summary"]["cells_failed_p1"] == 0
    assert payload["summary"]["missing_must_surfaces"] == 0
    assert payload["summary"]["private_backend_substitutes"] == 0
