"""ASV benchmarks for DecisionRepository persistence operations.

Measures create, get, get_by_plan, get_tree, and list_by_type performance.
"""

from __future__ import annotations

import sys
from datetime import UTC, datetime
from pathlib import Path

try:
    from cleveragents.domain.models.core.action import Action, ActionState
    from cleveragents.domain.models.core.decision import (
        Decision,
        DecisionType,
    )
    from cleveragents.domain.models.core.plan import (
        NamespacedName,
        Plan,
        PlanIdentity,
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )
    from cleveragents.infrastructure.database.models import Base
    from cleveragents.infrastructure.database.repositories import (
        ActionRepository,
        DecisionRepository,
        LifecyclePlanRepository,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.domain.models.core.action import Action, ActionState
    from cleveragents.domain.models.core.decision import (
        Decision,
        DecisionType,
    )
    from cleveragents.domain.models.core.plan import (
        NamespacedName,
        Plan,
        PlanIdentity,
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )
    from cleveragents.infrastructure.database.models import Base
    from cleveragents.infrastructure.database.repositories import (
        ActionRepository,
        DecisionRepository,
        LifecyclePlanRepository,
    )

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

_PLAN_ID = "01HV00000000000000BENCH001"


def _make_db():
    """Create an in-memory SQLite DB with all tables and prerequisites."""
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    sm = sessionmaker(bind=engine)
    session = sm()
    factory = lambda: session  # noqa: E731

    # Action prerequisite
    action_repo = ActionRepository(session_factory=factory)
    action = Action(
        namespaced_name=NamespacedName.parse("local/bench-decision-action"),
        description="Benchmark action",
        definition_of_done="Done",
        strategy_actor="local/s",
        execution_actor="local/e",
        state=ActionState.AVAILABLE,
        created_at=datetime(2026, 1, 1, tzinfo=UTC),
        updated_at=datetime(2026, 1, 1, tzinfo=UTC),
    )
    action_repo.create(action)
    session.commit()

    # Plan prerequisite
    plan_repo = LifecyclePlanRepository(session_factory=factory)
    now = datetime(2026, 3, 1, tzinfo=UTC)
    plan = Plan(
        identity=PlanIdentity(plan_id=_PLAN_ID, attempt=1),
        namespaced_name=NamespacedName(namespace="local", name="bench-plan"),
        action_name="local/bench-decision-action",
        description="Benchmark plan",
        definition_of_done="Done",
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.PROCESSING,
        strategy_actor="local/s",
        execution_actor="local/e",
        timestamps=PlanTimestamps(created_at=now, updated_at=now),
        created_by="bench",
        tags=[],
        reusable=True,
        read_only=False,
    )
    plan_repo.create(plan)
    session.commit()

    return session, factory


def _make_decision(seq=0, parent_id=None, dtype=DecisionType.PROMPT_DEFINITION):
    return Decision(
        plan_id=_PLAN_ID,
        parent_decision_id=parent_id,
        sequence_number=seq,
        decision_type=dtype,
        question="Benchmark question?",
        chosen_option="Benchmark option",
    )


class TimeDecisionCreate:
    """Benchmark decision creation."""

    timeout = 60

    def setup(self):
        self.session, self.factory = _make_db()
        self.repo = DecisionRepository(session_factory=self.factory)
        self._seq = 100

    def time_create_single(self):
        self._seq += 1
        d = _make_decision(seq=self._seq, dtype=DecisionType.STRATEGY_CHOICE)
        self.repo.create(d)
        self.session.commit()


class TimeDecisionGet:
    """Benchmark decision retrieval."""

    timeout = 60

    def setup(self):
        self.session, self.factory = _make_db()
        self.repo = DecisionRepository(session_factory=self.factory)
        d = _make_decision()
        self.repo.create(d)
        self.session.commit()
        self.decision_id = d.decision_id

    def time_get_by_id(self):
        self.repo.get(self.decision_id)


class TimeDecisionGetByPlan:
    """Benchmark get_by_plan with 50 pre-seeded decisions."""

    timeout = 60

    def setup(self):
        self.session, self.factory = _make_db()
        self.repo = DecisionRepository(session_factory=self.factory)
        root = _make_decision(seq=0)
        self.repo.create(root)
        root_id = root.decision_id
        for i in range(1, 50):
            d = _make_decision(
                seq=i,
                parent_id=root_id,
                dtype=DecisionType.STRATEGY_CHOICE,
            )
            self.repo.create(d)
        self.session.commit()

    def time_get_by_plan(self):
        self.repo.get_by_plan(_PLAN_ID)


class TimeDecisionTree:
    """Benchmark get_tree with a 3-level tree."""

    timeout = 60

    def setup(self):
        self.session, self.factory = _make_db()
        self.repo = DecisionRepository(session_factory=self.factory)

        root = _make_decision(seq=0)
        self.repo.create(root)
        self.root_id = root.decision_id

        seq = 1
        for _ in range(3):
            child = _make_decision(
                seq=seq,
                parent_id=root.decision_id,
                dtype=DecisionType.STRATEGY_CHOICE,
            )
            self.repo.create(child)
            for _ in range(2):
                seq += 1
                gc = _make_decision(
                    seq=seq,
                    parent_id=child.decision_id,
                    dtype=DecisionType.IMPLEMENTATION_CHOICE,
                )
                self.repo.create(gc)
            seq += 1
        self.session.commit()

    def time_get_tree(self):
        self.repo.get_tree(self.root_id)


class TimeDecisionListByType:
    """Benchmark list_by_type with pre-seeded typed decisions."""

    timeout = 60

    def setup(self):
        self.session, self.factory = _make_db()
        self.repo = DecisionRepository(session_factory=self.factory)

        root = _make_decision(seq=0)
        self.repo.create(root)
        root_id = root.decision_id

        for i in range(1, 20):
            d = _make_decision(
                seq=i,
                parent_id=root_id,
                dtype=DecisionType.STRATEGY_CHOICE,
            )
            self.repo.create(d)
        for i in range(20, 30):
            d = _make_decision(
                seq=i,
                parent_id=root_id,
                dtype=DecisionType.IMPLEMENTATION_CHOICE,
            )
            self.repo.create(d)
        self.session.commit()

    def time_list_strategy_choices(self):
        self.repo.list_by_type(_PLAN_ID, "strategy_choice")

    def time_list_implementation_choices(self):
        self.repo.list_by_type(_PLAN_ID, "implementation_choice")
