"""Characterization: Planner port inversion must not change frozen selections."""

import inspect
import json
from pathlib import Path

from src.domain.app_blocks.compiler import compile_install_plan
from src.domain.app_blocks.planner import select_capabilities
from src.domain.app_blocks.ports import CapabilityPlanner
from src.domain.projects.discovery_schemas import DiscoverySpec, ProductDefinition

ROOT = Path(__file__).resolve().parents[1]
BEFORE = json.loads(
    (ROOT / "docs/audits/fixtures/13b_b2_before/trials.json").read_text(encoding="utf-8")
)


def _raw(prompt: str) -> DiscoverySpec:
    return DiscoverySpec(product=ProductDefinition(purpose=prompt))


def test_compiler_depends_on_planner_port_not_rules():
    source = inspect.getsource(compile_install_plan)
    parameter = inspect.signature(compile_install_plan).parameters["planner"]
    assert "planner" in source
    assert "RULES" not in source
    assert parameter.annotation == CapabilityPlanner | None


def test_default_adapter_matches_injected_select_capabilities():
    spec = _raw("Staff product catalog")
    default = compile_install_plan(spec)
    injected = compile_install_plan(spec, planner=select_capabilities)
    assert default.model_dump() == injected.model_dump()
    assert default.requested_capabilities == ["catalog_product"]


def test_injected_planner_replaces_matching_policy():
    def empty_planner(_intent):
        return []

    spec = _raw("Staff product catalog")
    plan = compile_install_plan(spec, planner=empty_planner)
    assert plan.requested_capabilities == []
    assert plan.blocks == []


def test_before_score_snapshot_still_records_frozen_control():
    crm = next(row for row in BEFORE if row["id"] == "13A-002")
    assert crm["observation"]["predicted_product_blocks"] == ["forms.contact"]
    assert crm["expected_product_blocks"] == ["crm.lead", "crm.pipeline"]
