"""GR-06: workflow.approval App Block admission (second Backend-Complete
Capability Surface Admission, following the GR-05 pattern).

The approval-workflow Feature Pack (approval_request entity,
pending/approved/rejected/escalated workflow, 4 events) already existed
with zero App Block manifest and zero Planner reachability -- see
docs/audits/POST_B2_ARCHITECTURE_RECONCILIATION.md section 3. This admits
exactly one new App Block over that already-built backend: no new Cloud
primitive, no new persistence authority, no new workflow authority.

Full exit review: docs/audits/GR06_EXIT_REVIEW.md
"""

from pathlib import Path

from src.domain.app_blocks.compiler import compile_install_plan
from src.domain.app_blocks.planner import (
    _wants_workflow_approval,
    product_intent_from_spec,
    select_capabilities,
)
from src.domain.app_blocks.registry import load_manifests
from src.domain.projects.discovery_schemas import DiscoverySpec, ProductDefinition

ROOT = Path(__file__).resolve().parents[1]


def _raw(prompt: str) -> DiscoverySpec:
    return DiscoverySpec(product=ProductDefinition(purpose=prompt))


def test_catalog_admits_exactly_one_new_block():
    # GR-06 took the catalog from 20 -> 21; later gates admit further
    # blocks, so this checks internal consistency rather than a literal
    # count that would need updating at every future gate.
    from src.domain.app_blocks.canonical import CANONICAL_BLOCK_IDS

    manifests = load_manifests()
    assert "workflow.approval" in {m.id for m in manifests}
    assert len(manifests) == len(CANONICAL_BLOCK_IDS)


def test_approval_phrases_select_the_block():
    for phrase in (
        "we need an approval workflow",
        "build an internal approval queue",
        "requests need approval before proceeding",
        "expense requests require approval from an admin",
        "a manager can approve or reject each request",
    ):
        assert _wants_workflow_approval(phrase) is True, phrase


def test_negated_approval_language_stays_out():
    assert _wants_workflow_approval("does not need approval workflow") is False
    assert _wants_workflow_approval("without an approval queue for now") is False


def test_unrelated_approved_copy_stays_out():
    """Negative control: 'approved' used as a generic adjective, not a
    staff approval-request workflow, must not select the block."""
    assert _wants_workflow_approval("we only work with an approved vendor list") is False
    assert _wants_workflow_approval("this design was approved by the client") is False


def test_end_to_end_selection_and_install_plan_has_zero_gaps():
    prompt = (
        "We need an approval workflow so managers can approve or reject "
        "requests submitted by staff."
    )
    intent = product_intent_from_spec(_raw(prompt))
    predicted = {block for _, block, _ in select_capabilities(intent)}
    assert predicted == {"workflow.approval"}

    plan = compile_install_plan(_raw(prompt))
    assert plan.requested_capabilities == ["workflow_approval"]
    assert {b.id for b in plan.blocks} == {
        "workflow.approval",
        "admin.shell",
        "admin.record_table",
        "admin.record_detail",
    }
    assert plan.gaps == []
    assert plan.required_feature_packs == ["approval-workflow"]
    assert set(plan.required_primitives) <= {
        "auth.roles",
        "data.entity",
        "workflow.transition",
    }


def test_full_corpus_is_at_least_140_rows_128_admitted_zero_regression():
    # Was exactly 140/128 at GR-06 close; later gates append more rows, so
    # this checks GR-06's own floor and overall zero-regression rather than
    # a literal total that would need updating at every future gate.
    from scripts.measure_generation_reliability_13a import corpus, score
    from scripts.measure_planner_selection_13b_b2 import observe_rows

    rows = corpus(ROOT / "scripts/phase_13a_corpus.txt")
    assert len(rows) >= 140
    assert sum(row["oracle_kind"] == "admitted" for row in rows) >= 128
    assert sum(row["oracle_kind"] == "clarify" for row in rows) == 10
    assert sum(row["oracle_kind"] == "admission_required" for row in rows) == 2
    assert next(r for r in rows if r["id"] == "13A-119")["stratum"] == "boundary"
    assert next(r for r in rows if r["id"] == "13A-120")["stratum"] == "boundary"
    approval_ids = {f"13A-{n:03d}" for n in range(131, 141)}
    assert {r["stratum"] for r in rows if r["id"] in approval_ids} == {"approval"}

    observed = observe_rows(rows)
    admitted_total = sum(row["oracle_kind"] == "admitted" for row in rows)
    admitted = [row["observation"] for row in observed if row["oracle_kind"] == "admitted"]
    scored = score(admitted)
    assert scored["exact_product_match_rate"]["numerator"] == admitted_total
    assert scored["exact_product_match_rate"]["denominator"] == admitted_total
    assert scored["planner_precision"]["numerator"] == scored["planner_precision"]["denominator"]
    assert scored["planner_recall"]["numerator"] == scored["planner_recall"]["denominator"]
