"""ASV benchmarks for DecisionService DI resolution and operations.

Measures:
- Container resolution of DecisionService
- Decision recording through the service layer
- Decision tree retrieval through the service layer
"""

from __future__ import annotations

import sys
from datetime import UTC, datetime
from pathlib import Path
from unittest.mock import create_autospec

try:
    from cleveragents.application.services.decision_service import DecisionService
    from cleveragents.config.settings import Settings
    from cleveragents.domain.models.core.action import Action, ActionState
    from cleveragents.domain.models.core.decision import DecisionType
    from cleveragents.domain.models.core.plan import (
        NamespacedName,
        Plan,
        PlanIdentity,
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )
    from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.application.services.decision_service import DecisionService
    from cleveragents.config.settings import Settings
    from cleveragents.domain.models.core.action import Action, ActionState
    from cleveragents.domain.models.core.decision import DecisionType
    from cleveragents.domain.models.core.plan import (
        NamespacedName,
        Plan,
        PlanIdentity,
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )
    from cleveragents.infrastructure.database.unit_of_work import UnitOfWork


_PLAN_ID = "01HV00000000000000DJBENCH1"


def _make_uow() -> UnitOfWork:
    """Create a UoW backed by an in-memory SQLite database."""
    uow = UnitOfWork("sqlite:///:memory:")
    uow.init_database()
    return uow


def _seed_prerequisites(uow: UnitOfWork) -> None:
    """Create the action + plan needed to satisfy FK constraints."""
    with uow.transaction() as ctx:
        action_repo = ctx.actions
        action = Action(
            namespaced_name=NamespacedName.parse("local/bench-di-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)

    with uow.transaction() as ctx:
        plan_repo = ctx.lifecycle_plans
        now = datetime(2026, 3, 1, tzinfo=UTC)
        plan = Plan(
            identity=PlanIdentity(plan_id=_PLAN_ID, attempt=1),
            namespaced_name=NamespacedName(namespace="local", name="bench-di-plan"),
            action_name="local/bench-di-action",
            description="Benchmark DI 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)


class TimeDecisionServiceResolution:
    """Benchmark DecisionService resolution from the DI container."""

    timeout = 60

    def setup(self) -> None:
        import os

        os.environ["CLEVERAGENTS_DATABASE_URL"] = "sqlite:///:memory:"
        from cleveragents.application.container import get_container, reset_container

        reset_container()
        self.container = get_container()

    def time_decision_service_resolution(self) -> None:
        self.container.decision_service()

    def teardown(self) -> None:
        import os

        from cleveragents.application.container import reset_container

        reset_container()
        os.environ.pop("CLEVERAGENTS_DATABASE_URL", None)


class TimeDecisionRecord:
    """Benchmark decision recording through DecisionService."""

    timeout = 60

    def setup(self) -> None:
        self.uow = _make_uow()
        _seed_prerequisites(self.uow)
        mock_settings = create_autospec(Settings, instance=True)
        mock_settings.database_url = "sqlite:///:memory:"
        self.svc = DecisionService(settings=mock_settings, unit_of_work=self.uow)
        self._seq = 100

    def time_decision_record(self) -> None:
        self._seq += 1
        self.svc.record_decision(
            plan_id=_PLAN_ID,
            decision_type=DecisionType.STRATEGY_CHOICE,
            question="Benchmark question?",
            chosen_option="Benchmark option",
        )


class TimeDecisionTreeRetrieval:
    """Benchmark decision tree retrieval through DecisionService."""

    timeout = 60

    def setup(self) -> None:
        self.uow = _make_uow()
        _seed_prerequisites(self.uow)
        mock_settings = create_autospec(Settings, instance=True)
        mock_settings.database_url = "sqlite:///:memory:"
        self.svc = DecisionService(settings=mock_settings, unit_of_work=self.uow)

        # Build a small tree
        root = self.svc.record_decision(
            plan_id=_PLAN_ID,
            decision_type=DecisionType.PROMPT_DEFINITION,
            question="Benchmark question?",
            chosen_option="Benchmark option",
        )

        for _ in range(3):
            child = self.svc.record_decision(
                plan_id=_PLAN_ID,
                decision_type=DecisionType.STRATEGY_CHOICE,
                question="Benchmark question?",
                chosen_option="Benchmark option",
                parent_decision_id=root.decision_id,
            )
            for _ in range(2):
                self.svc.record_decision(
                    plan_id=_PLAN_ID,
                    decision_type=DecisionType.IMPLEMENTATION_CHOICE,
                    question="Benchmark question?",
                    chosen_option="Benchmark option",
                    parent_decision_id=child.decision_id,
                )

    def time_decision_tree_retrieval(self) -> None:
        self.svc.get_tree(_PLAN_ID)
