"""Implementation Playbook — the Berater renderer ("wie komme ich dort hin?").

After the Capability Delta Engine says WHAT is missing and the Optimization renderer says WHICH
measure first, the Playbook renderer says HOW to implement it. For one capability it assembles the
full journey from three sources:
  - curated playbook KNOWLEDGE (why / tools / process steps / evidence / how others do it) — the
    Reasoning Knowledge Acquisition layer under `knowledge/implementation_playbooks/`,
  - the regulatory LEVERAGE (which regulations a delivered capability closes) — reused from the
    Optimization renderer,
  - injected Procedure/Control/Evidence links (Execution-owned; empty until linked).

Pure, deterministic, computed-not-stored. Chains optimization -> playbook (acyclic). No new corpus,
no new meta-model class (freeze v1.0). Python 3.9 compatible.

The curated content is an EXPERT DRAFT, never a normative requirement. When no playbook knowledge
exists for a capability yet, the renderer emits a `status: missing` stub — the honest signal that
the bottleneck is CONTENT (Knowledge Acquisition), not software.
"""

from __future__ import annotations

from typing import Any, Dict, List, Optional

from ..optimization import OptimizationPlan
from .schemas import Playbook, PlaybookStep

_MISSING_WHY = "(Playbook-Inhalt fehlt — Knowledge Acquisition offen.)"
_DRAFT_DISCLAIMER = (
    "Kuratiertes Experten-Wissen (Erstentwurf), KEINE normative Anforderung. Tools/Schritte sind "
    "Empfehlungen, kein Pflichtkatalog; Controls werden aus der Execution-Schicht injiziert."
)


def _steps(raw: Any) -> List[PlaybookStep]:
    steps: List[PlaybookStep] = []
    for i, s in enumerate(raw or [], 1):
        steps.append(PlaybookStep(order=i, title=str(s.get("title", "")), detail=str(s.get("detail", ""))))
    return steps


def build_playbook(
    capability_id: str,
    knowledge: Optional[Dict[str, Any]] = None,
    closes_regulations: Optional[List[str]] = None,
    control_links: Optional[List[str]] = None,
) -> Playbook:
    """Assemble the implementation journey for ONE capability.

    `knowledge`: the curated playbook dict (None/empty -> a `missing` stub). `closes_regulations`:
    the regulations a delivered capability closes (leverage, from `covers_targets`). `control_links`:
    Execution-owned control refs, injected (default empty — no Execution data in Reasoning code).
    """
    closes = sorted(set(closes_regulations or []))
    if not knowledge:
        return Playbook(
            capability_id=capability_id, title=capability_id, why=_MISSING_WHY,
            closes_regulations=closes, leverage=len(closes), controls=list(control_links or []),
            status="missing", disclaimer=_DRAFT_DISCLAIMER,
        )
    return Playbook(
        capability_id=capability_id,
        title=str(knowledge.get("title", capability_id)),
        why=str(knowledge.get("why", "")),
        closes_regulations=closes,
        leverage=len(closes),
        tools=list(knowledge.get("tools", [])),
        process_steps=_steps(knowledge.get("process_steps")),
        expected_evidence=list(knowledge.get("expected_evidence", [])),
        controls=list(control_links or []),
        how_others_do_it=str(knowledge.get("how_others_do_it", "")),
        status=str(knowledge.get("status", "draft")),
        disclaimer=str(knowledge.get("disclaimer", _DRAFT_DISCLAIMER)),
    )


def playbooks_for_plan(
    plan: OptimizationPlan,
    knowledge_by_cap: Dict[str, Dict[str, Any]],
    top_k: Optional[int] = None,
    control_links_by_cap: Optional[Dict[str, List[str]]] = None,
) -> List[Playbook]:
    """Render playbooks for the highest-leverage measures of an OptimizationPlan (Roadmap -> How).

    Walks the ranked measures (top_k, or all) and builds each capability's playbook, using the
    measure's own `covers` as the regulations it closes. Measures without curated knowledge become
    `missing` stubs — surfacing exactly where playbook content is still owed.
    """
    links = control_links_by_cap or {}
    measures = plan.ranked_measures if top_k is None else plan.ranked_measures[: max(0, top_k)]
    return [
        build_playbook(
            m.capability_id, knowledge_by_cap.get(m.capability_id),
            closes_regulations=m.covers, control_links=links.get(m.capability_id),
        )
        for m in measures
    ]
