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

Does not invent an Inventory recipe family.
"""

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.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/inventory_freeze.receipt.txt"

GATED = (
    "payments.checkout",
    "membership.portal",
)

SMOKE = (
    ("I need to track inventory quantities for our products.", None, ("inventory.stock",)),
    ("Staff need to update stock levels.", None, ("inventory.stock",)),
    ("Build an inventory management screen for our repair parts.", None, ("inventory.stock",)),
    ("Track SKU, location, quantity and reorder level.", None, ("inventory.stock",)),
    (
        "Staff product catalog and inventory management. No checkout.",
        None,
        ("catalog.product", "inventory.stock"),
    ),
    (
        "Staff manage customer orders and inventory quantities. No checkout.",
        None,
        ("orders.order", "inventory.stock"),
    ),
)

CONTROLS = (
    ("Staff manage a product catalog. No checkout, orders, or billing.", None, ("catalog.product",)),
    ("Staff manage customer orders. No checkout, billing, or inventory.", None, ("orders.order",)),
    ("Staff need an invoice management screen. No checkout, orders, or catalog.", None, ("billing.invoice",)),
)

NEGATIVES = (
    ("Do not add inventory.", None, "inventory.stock"),
    ("No stock management.", None, "inventory.stock"),
    ("customer orders 3 items", None, "inventory.stock"),
    ("show product availability text", None, "inventory.stock"),
    ("Do not build warehouse features.", None, "inventory.stock"),
)


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)}
    on_disk = [
        recipe.id
        for catalog in load_recipe_catalogs()
        for recipe in catalog.recipes
        if catalog.batch != "marketing_coverage"
        and catalog.batch.startswith("inventory")
    ]
    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 not ok:
            failures.append(prompt)
        rows.append({"prompt": prompt, "kind": "smoke", "matched": matched, "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
        ok = matched == expected and set(required) <= ids
        ok = ok and "inventory.stock" not in ids
        if not ok:
            failures.append(prompt)
        rows.append({"prompt": prompt, "kind": "control", "matched": matched, "ids": sorted(ids), "pass": ok})
    for prompt, expected, stripped in NEGATIVES:
        recipe = _recipe(prompt)
        ids = _ids(prompt)
        matched = None if recipe is None else recipe.id
        ok = matched == expected and stripped not in ids
        if not ok:
            failures.append(prompt)
        rows.append({"prompt": prompt, "kind": "negative", "matched": matched, "ids": sorted(ids), "pass": ok})
    payload = {
        "generated_at": datetime.now(UTC).isoformat(),
        "live_recipes": len(live),
        "on_disk_inventory_recipes": on_disk,
        "failures": failures,
        "pass": not failures and on_disk == [],
        "rows": rows,
    }
    if on_disk:
        payload["failures"] = [*failures, "on_disk_inventory_recipes"]
        payload["pass"] = False
    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())
