"""Capability Model Phase 2: crm.organization fills the one real CRM gap
(contacts and companies weren't distinguished). Not a new Architecture
family -- crm.customer/crm.lead/crm.pipeline already exist; this follows the
same admission pattern within the existing crm family.
"""

from pathlib import Path

from src.domain.app_blocks.canonical import CANONICAL_BLOCK_IDS
from src.domain.app_blocks.catalogs import default_known_packs
from src.domain.app_blocks.execution import assert_install_plan_installable
from src.domain.app_blocks.generated_product_conformance_12h import (
    KernelDeniedError,
    PlatformKernel,
)
from src.domain.app_blocks.planner import ProductIntent, select_capabilities
from src.domain.app_blocks.registry import load_default_registry
from src.domain.starter_library.catalog import known_contract_ids
from tests.test_phase11_pack_migration_materialization import _captured_composition

ROOT = Path(__file__).resolve().parents[1]
STARTER_SLOTS = {
    "list": "record.table",
    "detail": "record.detail",
    "create": "record.create",
    "edit": "record.edit",
    "empty": "state.empty",
}


def organization_composition():
    return _captured_composition(
        "alembic/versions/151_organization_records_pack.py", "organization-records"
    )


def _ids(intent: ProductIntent) -> set[str]:
    return {block_id for _cap, block_id, _reason in select_capabilities(intent)}


def test_crm_organization_runtime_is_canonical_without_new_kernel():
    registry = load_default_registry()
    block = registry.require("crm.organization")
    canonical = registry.canonical.require("crm.organization")
    assert block.status == "implemented"
    assert block.lifecycle == "stable"
    assert "crm.organization" in CANONICAL_BLOCK_IDS
    assert canonical.installation.feature_packs == ("organization-records",)
    primitives = {dep.id for dep in canonical.requires if dep.kind == "primitive"}
    assert primitives == {"data.entity"}
    assert "organization-records" in default_known_packs()
    composition = organization_composition()
    entity = composition["entities"][0]
    assert entity["entity_key"] == "organization"
    keys = {field["key"] for field in entity["schema"]["fields"]}
    assert keys == {"name", "website", "industry", "phone", "notes", "status"}


def test_positive_intent_selects_organization():
    for prompt in (
        "Staff need organization records for our B2B accounts.",
        "Manage companies and their industries.",
        "Build a company directory for staff.",
    ):
        ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
        assert "crm.organization" in ids, prompt


def test_negative_intent_skips_organization():
    for prompt in (
        "Client records for the firm. Do not add organization records.",
        "Staff CRM. No company records needed.",
    ):
        ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
        assert "crm.organization" not in ids, prompt


def test_organization_and_customer_compose_without_merging_stores():
    prompt = "Staff manage customer records and organization records."
    ids = _ids(ProductIntent(purpose=prompt, source_prompt=prompt, staff_review=True))
    assert {"crm.customer", "crm.organization"} <= ids


def test_organization_reuses_record_starter_contracts():
    registry = load_default_registry()
    block = registry.require("crm.organization")
    contracts = {slot.id: slot.component_contract for slot in block.slots if slot.component_contract}
    assert STARTER_SLOTS.items() <= contracts.items()
    assert "crm.organization.list" not in known_contract_ids()


def test_organization_runtime_crud_is_staff_managed_records():
    kernel = PlatformKernel(namespace="organization-capability")
    kernel.as_anonymous()
    import pytest

    with pytest.raises(KernelDeniedError):
        kernel.create_record("organization", {"name": "Acme"})
    kernel.as_staff()
    created = kernel.create_record(
        "organization", {"name": "Acme Corp", "industry": "Manufacturing", "status": "active"}
    )
    listed = kernel.list_records("organization")
    assert listed[0]["id"] == created["id"]
    kernel.patch_record("organization", created["id"], {"status": "inactive"})
    read = kernel.get_record("organization", created["id"])
    assert read["status"] == "inactive"


def test_materialized_organization_hosts_use_records():
    import json
    from src.domain.app_blocks.hosts import merge_host_map

    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()))
        rows = {h["slot"]: h for h in hosts["hosts"] if h["block"] == "crm.organization"}
        assert {"list", "detail", "create", "edit", "empty"} <= set(rows)
        for slot in ("list", "detail", "create", "edit"):
            path = rows[slot]["implementation"].partition("#")[0]
            source = (root / path).read_text(encoding="utf-8")
            assert "organization" in source
