"""11G2: catalog.product App Block on a standalone catalog_item entity."""
import json
from pathlib import Path

from src.domain.app_blocks import compiler
from src.domain.app_blocks.canonical import feature_pack_only_aliases
from src.domain.app_blocks.catalogs import FEATURE_PACK_ALIASES, default_known_packs
from src.domain.app_blocks.hosts import merge_host_map
from src.domain.app_blocks.planner import ProductIntent, select_capabilities
from src.domain.app_blocks.public import _BLOCK_COPY
from src.domain.app_blocks.registry import load_default_registry
from src.domain.feature_packs.crm_authorization import staff_policy
from src.domain.feature_packs.ownership import validate_composition_ownership_contracts

from tests.test_phase11_pack_migration_materialization import _captured_composition

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


def catalog_composition():
    return _captured_composition("alembic/versions/145_product_catalog_pack.py", "product-catalog")


def test_catalog_is_a_block_not_checkout():
    registry = load_default_registry()
    assert "catalog.product" not in FEATURE_PACK_ALIASES
    assert "catalog.product" not in feature_pack_only_aliases()
    block = registry.require("catalog.product")
    assert block.id == "catalog.product"
    canonical = registry.canonical.require("catalog.product")
    assert canonical.installation.feature_packs == ("product-catalog",)
    assert canonical.id != "product-catalog"
    assert {dep.id for dep in canonical.requires if dep.kind == "primitive"} == {"data.entity"}
    assert "payment-checkout" not in canonical.installation.feature_packs


def test_planner_matches_catalog_phrases_only():
    hit = select_capabilities(ProductIntent(purpose="Staff manage a product catalog"))
    assert any(block_id == "catalog.product" for _cap, block_id, _reason in hit)
    miss = select_capabilities(ProductIntent(
        purpose="Add Stripe checkout products and a Shopify product catalog later"
    ))
    assert not any(block_id == "catalog.product" for _cap, block_id, _reason in miss)


def test_public_label_does_not_leak_the_raw_id():
    label = _BLOCK_COPY["catalog.product"]
    assert label == "Product catalog"
    assert label != "catalog.product"


def test_install_plan_resolves_product_catalog_pack(monkeypatch):
    registry = load_default_registry()
    monkeypatch.setattr(
        compiler,
        "select_capabilities",
        lambda _intent: [("catalog_product", "catalog.product", "Selected.")],
    )
    plan = compiler.compile_install_plan(None, registry=registry)
    assert not plan.unsatisfiable
    assert plan.required_feature_packs == ["product-catalog"]
    assert "payment-checkout" not in plan.required_feature_packs
    assert "data.entity" in plan.required_primitives
    assert "catalog.product" in {block.id for block in plan.blocks}


def test_missing_pack_is_an_honest_gap_not_a_checkout_fallback(monkeypatch):
    registry = load_default_registry()
    monkeypatch.setattr(
        compiler,
        "select_capabilities",
        lambda _intent: [("catalog_product", "catalog.product", "Selected.")],
    )
    plan = compiler.compile_install_plan(
        None, registry=registry, known_packs=default_known_packs() - {"product-catalog"}
    )
    assert plan.unsatisfiable
    assert any(gap.id == "product-catalog" for gap in plan.gaps)
    assert not any(gap.id == "payment-checkout" for gap in plan.gaps)


def test_persistence_is_catalog_item_not_checkout_product():
    composition = catalog_composition()
    validate_composition_ownership_contracts(composition)
    assert composition["function_slugs"] == composition["connector_actions"] == []
    entity = composition["entities"][0]
    assert entity["entity_key"] == "catalog_item"
    assert entity["schema"]["access_policy"] == staff_policy()
    assert not entity.get("rls_enabled") and not entity.get("owner_managed")
    assert "workflow" not in entity["schema"]
    keys = {field["key"] for field in entity["schema"]["fields"]}
    assert keys == {"name", "description", "sku", "price_amount", "currency", "status"}
    assert "stripe_product_id" not in keys and "stripe_price_id" not in keys


def test_materialized_catalog_hosts_use_records_not_checkout():
    for framework in ("html", "nuxt_app", "react_app"):
        root = ROOT / "boilerplates" / framework
        hosts = merge_host_map(json.loads((root / "p2hs/app-block-hosts.json").read_text()))
        catalog = {h["slot"]: h for h in hosts["hosts"] if h["block"] == "catalog.product"}
        assert {"list", "detail", "create", "edit", "empty"} <= set(catalog)
        for slot in ("list", "detail", "create", "edit"):
            path = catalog[slot]["implementation"].partition("#")[0]
            source = (root / path).read_text(encoding="utf-8")
            assert "catalog_item" in source
            assert "stripe_product_id" not in source
            assert "createCheckout" not in source
            assert "/api/checkout" not in source
        assert catalog["empty"]["implementation"]
