"""Capability Model invariants: catalog existence must not be conflated with
Codegen-selectable availability.

App Block manifests and Feature Pack overlays each carry `lifecycle`/
`readiness` alongside the pre-existing `status`/`selectable` fields. These
tests enforce the invariants that motivated adding them, without requiring a
disruptive rewrite of either existing signal.
"""

from src.domain.app_blocks.canonical import CANONICAL_BLOCK_IDS
from src.domain.app_blocks.registry import load_default_registry
from src.domain.feature_packs.catalog_v2 import CATALOG_OVERLAYS

_TERMINAL_LIFECYCLES = ("reserved", "deprecated", "internal")
_SELECTABLE_LIFECYCLES = ("stable", "preview")


def test_all_canonical_app_blocks_default_to_stable_and_unchanged_behavior():
    # Capability Model Phase 6 (retroactive classification): every admitted
    # App Block, old and new, is lifecycle=stable/readiness=implemented by
    # default -- no manifest needed an explicit edit to satisfy this.
    registry = load_default_registry()
    for block_id in CANONICAL_BLOCK_IDS:
        manifest = registry.require(block_id)
        assert manifest.lifecycle == "stable", block_id
        assert manifest.readiness == "implemented", block_id
        assert manifest.implemented is True, block_id


def test_terminal_lifecycle_app_blocks_are_never_implemented():
    registry = load_default_registry()
    for manifest in registry.all():
        if manifest.lifecycle in _TERMINAL_LIFECYCLES:
            assert manifest.implemented is False, manifest.id
        if manifest.readiness != "implemented":
            assert manifest.implemented is False, manifest.id


def test_deprecated_or_compatibility_app_blocks_declare_a_replacement():
    registry = load_default_registry()
    ids = CANONICAL_BLOCK_IDS
    for manifest in registry.all():
        if manifest.lifecycle in ("deprecated", "compatibility"):
            assert manifest.replacement, manifest.id
            assert manifest.replacement in ids, (manifest.id, manifest.replacement)


def test_replacement_target_is_not_itself_deprecated():
    registry = load_default_registry()
    for manifest in registry.all():
        if not manifest.replacement:
            continue
        target = registry.get(manifest.replacement)
        if target is not None:
            assert target.lifecycle != "deprecated", (manifest.id, manifest.replacement)


def test_every_app_block_has_family_or_owner():
    registry = load_default_registry()
    for manifest in registry.all():
        assert manifest.family or manifest.owner, manifest.id


def test_feature_pack_selectable_matches_lifecycle_and_readiness():
    for slug, overlay in CATALOG_OVERLAYS.items():
        planner = overlay["planner"]
        expected = planner.lifecycle in _SELECTABLE_LIFECYCLES and planner.readiness == "implemented"
        assert planner.selectable == expected, slug


def test_legacy_aggregate_packs_are_lifecycle_compatibility():
    for slug, overlay in CATALOG_OVERLAYS.items():
        compatibility = overlay.get("compatibility")
        legacy = bool(compatibility and compatibility.get("legacy_aggregate"))
        planner = overlay["planner"]
        if legacy:
            assert planner.lifecycle == "compatibility", slug
        if planner.lifecycle == "compatibility":
            assert legacy, slug


def test_crm_pipeline_and_client_portal_are_the_known_compatibility_packs():
    compatibility_packs = {
        slug for slug, overlay in CATALOG_OVERLAYS.items() if overlay["planner"].lifecycle == "compatibility"
    }
    assert compatibility_packs == {"crm-pipeline", "client-portal"}


def test_payment_checkout_stays_stable_as_the_provider_gated_exception():
    # Wave 5 admitted payments.checkout as a dual-namespace App Block over the
    # existing payment-checkout pack. The pack stays lifecycle=stable/selectable.
    from src.domain.app_blocks.canonical import DUAL_NAMESPACE_IDS, feature_pack_only_aliases

    assert "payments.checkout" not in feature_pack_only_aliases()
    assert "payments.checkout" in DUAL_NAMESPACE_IDS
    planner = CATALOG_OVERLAYS["payment-checkout"]["planner"]
    assert planner.lifecycle == "stable"
    assert planner.readiness == "implemented"
    assert planner.selectable is True
