"""Architecture Lane Catalog production-path planner smoke.

Exercises the same Core path production Discovery uses after a turn:
customer initial_prompt + paraphrased spec → planner → public_composition.
Does not create production projects or call OpenAI.
"""

from __future__ import annotations

import json
from datetime import UTC, datetime
from pathlib import Path

from src.domain.app_blocks.planner import product_intent_from_spec, select_capabilities
from src.domain.app_blocks.public import public_composition
from src.domain.app_blocks.vertical_recipes import (
    load_recipe_catalogs,
    load_recipes,
    match_recipe_for_intent,
)
from src.domain.projects.discovery_schemas import (
    Actor,
    AuthenticationSpec,
    DiscoverySpec,
    Entity,
    ProductDefinition,
    TenancySpec,
    Workflow,
)

ROOT = Path(__file__).resolve().parents[1]
RECEIPT = ROOT / "src/domain/app_blocks/recipes/catalog_04.receipt.txt"

GATED = (
    "orders.order",
    "payments.checkout",
    "billing.invoice",
    "inventory.stock",
    "membership.portal",
)

SMOKE = (
    ("product catalog", None, ("catalog.product",)),
    ("service catalog", "service_catalog", ("catalog.product",)),
    ("consulting service catalog", "service_catalog", ("catalog.product",)),
    ("course catalog", "course_catalog", ("catalog.product",)),
    ("contractor quote crm", "contractor_quote_crm", ("forms.quote_request", "crm.customer")),
    ("product catalog. No checkout, orders, or billing.", None, ("catalog.product",)),
)

CONTROLS = (
    ("appointment booking", None, ("booking.appointment",)),
    ("student admissions CRM", "student_admissions", ("crm.customer", "case.management")),
    ("support ticket system", None, ("support.ticket",)),
    ("case management", None, ("case.management",)),
    ("document library", None, ("documents",)),
)

NEGATIVES = (
    ("Course catalog. Do not add catalog.", "course_catalog", "catalog.product"),
)


def _spec(prompt: str) -> DiscoverySpec:
    return DiscoverySpec(
        product=ProductDefinition(
            purpose="track records for a consultancy",
            first_build_goal="Staff review submitted records",
        ),
        original_intent=prompt,
        actors=[Actor(id="staff", name="Staff counselor")],
        workflows=[Workflow(id="review", name="Staff review", description="Review records")],
        entities=[Entity(id="record", name="Record", description="A record")],
        tenancy=TenancySpec(model="single_workspace"),
        authentication=AuthenticationSpec(required=False),
    )


def _ids(prompt: str) -> set[str]:
    intent = product_intent_from_spec(_spec(prompt), source_prompt=prompt)
    return {block_id for _cap, block_id, _reason in select_capabilities(intent)}


def _recipe(prompt: str):
    return match_recipe_for_intent(product_intent_from_spec(_spec(prompt), source_prompt=prompt))


def run_smoke() -> dict:
    rows = []
    failures = []
    live = {recipe.id for recipe in load_recipes(composition_ready_only=True)}
    flags = {
        catalog.batch: catalog.ready_for_fast_lane_composition
        for catalog in load_recipe_catalogs()
    }
    for prompt, expected, required in SMOKE:
        recipe = _recipe(prompt)
        ids = _ids(prompt)
        matched = None if recipe is None else recipe.id
        ok = set(required) <= ids and matched == expected
        ok = ok and not (ids & set(GATED))
        if expected == "contractor_quote_crm":
            ok = ok and "catalog.product" not in ids
        if "catalog.product" in required:
            ok = ok and "booking.appointment" not in ids
        if not ok:
            failures.append(prompt)
        rows.append(
            {
                "prompt": prompt,
                "kind": "smoke",
                "matched": matched,
                "expected": expected,
                "ids": sorted(ids),
                "pass": ok,
            }
        )
    for prompt, expected, required in CONTROLS:
        recipe = _recipe(prompt)
        ids = _ids(prompt)
        matched = None if recipe is None else recipe.id
        if expected is None:
            ok = recipe is None and set(required) <= ids
        else:
            ok = matched == expected and set(required) <= ids
        ok = ok and "catalog.product" not in ids
        ok = ok and not (ids & set(GATED))
        if not ok:
            failures.append(prompt)
        rows.append(
            {
                "prompt": prompt,
                "kind": "control",
                "matched": matched,
                "expected_recipe": expected,
                "ids": sorted(ids),
                "pass": ok,
            }
        )
    for prompt, expected, stripped in NEGATIVES:
        recipe = _recipe(prompt)
        ids = _ids(prompt)
        ok = (None if recipe is None else recipe.id) == expected and stripped not in ids
        if not ok:
            failures.append(prompt)
        rows.append(
            {
                "prompt": prompt,
                "kind": "negative",
                "matched": None if recipe is None else recipe.id,
                "stripped": stripped,
                "ids": sorted(ids),
                "pass": ok,
            }
        )
    gated_ids = [
        recipe.id
        for catalog in load_recipe_catalogs()
        if not catalog.ready_for_fast_lane_composition
        for recipe in catalog.recipes
    ]
    payload = {
        "generated_at": datetime.now(UTC).isoformat(),
        "live_recipes": len(live),
        "booking_selectable": flags.get("booking_03") is True,
        "catalog_selectable": flags.get("catalog_04") is True,
        "gated_recipe_ids": gated_ids,
        "failures": failures,
        "pass": not failures,
        "rows": rows,
    }
    return payload


def main() -> int:
    payload = run_smoke()
    print(json.dumps({k: payload[k] for k in payload if k != "rows"}, indent=2))
    for row in payload["rows"]:
        mark = "PASS" if row["pass"] else "FAIL"
        print(f"{mark} {row['kind']:8} {row['prompt']!r} matched={row.get('matched')} ids={row['ids']}")
    if RECEIPT.is_file() and payload["pass"]:
        text = RECEIPT.read_text(encoding="utf-8")
        if "production_proven=pending_this_slice" in text:
            RECEIPT.write_text(
                text.replace("production_proven=pending_this_slice", "production_proven=local_smoke_pass"),
                encoding="utf-8",
            )
    return 0 if payload["pass"] else 1


if __name__ == "__main__":
    raise SystemExit(main())
