"""Tests for the Implementation Playbook renderer (the Berater view, "wie komme ich dort hin?").

Acceptance: for one capability, assemble the journey (why / closes-which-regulations / tools /
process / evidence / controls) from curated knowledge + leverage + injected Execution links; chain
the Optimization Roadmap into per-measure playbooks; surface capabilities without content as honest
`missing` stubs. Curated content is an expert draft, never normative.
"""

from __future__ import annotations

from compliance.optimization import regulatory_leverage
from compliance.playbook import Playbook, build_playbook, playbooks_for_plan

SBOM = {
    "title": "SBOM aufbauen",
    "why": "CRA verlangt ein Komponenten-Inventar.",
    "tools": ["CycloneDX", "Syft"],
    "process_steps": [{"title": "Format wählen", "detail": "CycloneDX"}, {"title": "In CI erzeugen", "detail": ""}],
    "expected_evidence": ["sbom_per_release"],
    "how_others_do_it": "CI + Dependency-Track.",
    "status": "draft",
}


def test_build_playbook_full_journey():
    pb = build_playbook("sbom_creation", SBOM, closes_regulations=["CRA", "MaschinenVO"], control_links=["component_inventory"])
    assert pb.title == "SBOM aufbauen" and pb.status == "draft"
    assert pb.closes_regulations == ["CRA", "MaschinenVO"] and pb.leverage == 2
    assert pb.tools == ["CycloneDX", "Syft"]
    assert [s.order for s in pb.process_steps] == [1, 2]
    assert pb.process_steps[0].title == "Format wählen"
    assert pb.expected_evidence == ["sbom_per_release"]
    assert pb.controls == ["component_inventory"]            # injected from Execution
    assert pb.disclaimer                                     # always carries the expert-draft caveat


def test_missing_knowledge_is_honest_stub():
    pb = build_playbook("product_cyber_risk_assessment", None, closes_regulations=["CRA", "MaschinenVO"])
    assert pb.status == "missing"                            # the content-owed signal
    assert pb.leverage == 2 and pb.closes_regulations == ["CRA", "MaschinenVO"]  # leverage still known
    assert pb.tools == [] and pb.process_steps == []
    assert "Knowledge Acquisition" in pb.why


def test_closes_regulations_deduped_and_sorted():
    pb = build_playbook("x", SBOM, closes_regulations=["MaschinenVO", "CRA", "CRA"])
    assert pb.closes_regulations == ["CRA", "MaschinenVO"] and pb.leverage == 2


def test_controls_default_empty_no_execution_data():
    pb = build_playbook("x", SBOM, closes_regulations=["CRA"])
    assert pb.controls == []                                 # no Execution data unless injected


def test_playbooks_for_plan_orders_by_leverage_and_stubs_missing():
    caps = {"sbom_creation": ["CRA"], "pcra": ["CRA", "MaschinenVO"], "guards": ["MaschinenVO"]}
    plan = regulatory_leverage(caps)
    pbs = playbooks_for_plan(plan, {"sbom_creation": SBOM}, top_k=3)
    assert [p.capability_id for p in pbs][0] == "pcra"       # highest leverage first
    by = {p.capability_id: p for p in pbs}
    assert by["pcra"].status == "missing" and by["pcra"].leverage == 2
    assert by["sbom_creation"].status == "draft"            # has content
    assert by["guards"].status == "missing"


def test_playbooks_for_plan_top_k_and_injected_controls():
    caps = {"a": ["CRA", "MaschinenVO"], "b": ["CRA"], "c": ["CRA"]}
    plan = regulatory_leverage(caps)
    pbs = playbooks_for_plan(plan, {}, top_k=1, control_links_by_cap={"a": ["ctrl_1"]})
    assert len(pbs) == 1 and pbs[0].capability_id == "a"
    assert pbs[0].controls == ["ctrl_1"]


def test_playbooks_for_plan_empty():
    plan = regulatory_leverage({})
    assert playbooks_for_plan(plan, {}) == []


def test_deterministic():
    caps = {"a": ["CRA", "MaschinenVO"], "b": ["CRA"]}
    plan = regulatory_leverage(caps)
    a = [p.capability_id for p in playbooks_for_plan(plan, {})]
    b = [p.capability_id for p in playbooks_for_plan(plan, {})]
    assert a == b


def test_returns_playbook_type():
    assert isinstance(build_playbook("x", None), Playbook)
