"""ASV benchmarks for plan correct tree wiring (issue #606).

Measures overhead of building the decision tree adjacency list and
influence DAG edges from DecisionService output, and passing them
through to CorrectionService.analyze_impact() and
CorrectionService.execute_correction().
"""

from __future__ import annotations

import sys
from pathlib import Path
from types import SimpleNamespace
from typing import ClassVar

try:
    from cleveragents.application.services.correction_service import CorrectionService
    from cleveragents.domain.models.core.correction import CorrectionMode
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.application.services.correction_service import CorrectionService
    from cleveragents.domain.models.core.correction import CorrectionMode

_PLAN_ID = "01BENCH_PLAN_000000000000001"
_ROOT = "DEC-BENCH-ROOT"


def _make_decision(decision_id: str, parent_decision_id: str | None) -> SimpleNamespace:
    """Create a minimal decision-like namespace."""
    return SimpleNamespace(
        decision_id=decision_id,
        parent_decision_id=parent_decision_id,
    )


def _build_chain(depth: int) -> list[SimpleNamespace]:
    """Build a linear chain of decisions."""
    decisions: list[SimpleNamespace] = [_make_decision(_ROOT, None)]
    for i in range(1, depth):
        decisions.append(_make_decision(f"{_ROOT}_c{i}", decisions[-1].decision_id))
    return decisions


def _build_tree_from_decisions(
    decisions: list[SimpleNamespace],
) -> dict[str, list[str]]:
    """Replicate the tree-building logic from correct_decision()."""
    tree: dict[str, list[str]] = {}
    for d in decisions:
        if d.parent_decision_id is not None:
            tree.setdefault(d.parent_decision_id, []).append(d.decision_id)
    return tree


# ---------------------------------------------------------------------------
# Benchmarks
# ---------------------------------------------------------------------------


class TreeBuildingSuite:
    """Benchmark decision tree adjacency-list construction."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["chain_depth"]

    def setup(self, chain_depth: int) -> None:
        """Prepare decision chains."""
        self.decisions = _build_chain(chain_depth)

    def time_build_tree(self, chain_depth: int) -> None:
        """Time the tree-building loop from correct_decision."""
        _build_tree_from_decisions(self.decisions)


class AnalyzeWithTreeSuite:
    """Benchmark analyze_impact when decision_tree is pre-built."""

    params: ClassVar[list[int]] = [10, 100, 500]
    param_names: ClassVar[list[str]] = ["chain_depth"]

    def setup(self, chain_depth: int) -> None:
        """Prepare CorrectionService and tree."""
        self.svc = CorrectionService()
        decisions = _build_chain(chain_depth)
        self.tree = _build_tree_from_decisions(decisions)
        self.edges: dict[str, list[str]] = {}
        # Create a correction request for the root
        self.req = self.svc.request_correction(
            plan_id=_PLAN_ID,
            target_decision_id=_ROOT,
            mode=CorrectionMode.REVERT,
            guidance="benchmark",
        )

    def time_analyze_impact_with_tree(self, chain_depth: int) -> None:
        """Time analyze_impact with pre-built tree."""
        # Re-create request each iteration to avoid status issues
        svc = CorrectionService()
        req = svc.request_correction(
            plan_id=_PLAN_ID,
            target_decision_id=_ROOT,
            mode=CorrectionMode.REVERT,
            guidance="benchmark",
        )
        svc.analyze_impact(
            req.correction_id,
            decision_tree=self.tree,
            influence_edges=self.edges,
        )
