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

Does not invent a Membership 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/membership_freeze.receipt.txt"

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

SMOKE = (
    ("Staff need to manage our association members.", None, ("membership.member",)),
    ("Track member type, start date, end date and active status.", None, ("membership.member",)),
    ("Build a membership management screen.", None, ("membership.member",)),
    ("We need a roster of club members and their membership status.", None, ("membership.member",)),
    ("We need a roster of active and inactive members.", None, ("membership.member",)),
    ("Create a membership database for our professional organization.", None, ("membership.member",)),
    (
        "Staff customer records and membership management. No checkout.",
        None,
        ("crm.customer", "membership.member"),
    ),
    (
        "Staff invoice management and membership management. No checkout.",
        None,
        ("billing.invoice", "membership.member"),
    ),
    (
        "Staff document management and membership management. No checkout.",
        None,
        ("documents", "membership.member"),
    ),
)

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 membership management.", None, "membership.member"),
    ("We don't have members.", None, "membership.member"),
    ("We don't track members.", None, "membership.member"),
    ("Do not build a member roster.", None, "membership.member"),
    ("Add staff members", None, "membership.member"),
    ("Admin can add and remove staff members.", None, "membership.member"),
    ("Track board members, meetings, agendas and minutes.", None, "membership.member"),
    ("Conversation members can reply.", None, "membership.member"),
    ("Users can sign up and log in", None, "membership.member"),
    ("Users pay $29/month for access.", None, "membership.member"),
    ("Offer monthly subscriptions", None, "membership.member"),
    ("Do not build a member portal.", None, "membership.member"),
)


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 ("membership" in recipe.id or catalog.batch.startswith("membership"))
    ]
    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 "membership.member" 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_membership_recipes": on_disk,
        "failures": failures,
        "pass": not failures and on_disk == [],
        "rows": rows,
    }
    if on_disk:
        payload["failures"] = [*failures, "on_disk_membership_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())
