"""ASV benchmarks for the validation-gated apply pipeline.

Measures the performance of:
- ApplyResult model construction
- Validation count extraction
- apply_with_validation_gate() with mock lifecycle
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock

try:
    from cleveragents.application.services.plan_apply_service import (
        ApplyOutcome,
        ApplyResult,
        PlanApplyService,
    )
    from cleveragents.domain.models.core.change import (
        ChangeEntry,
        ChangeOperation,
        SpecChangeSet,
    )
    from cleveragents.domain.models.core.plan import (
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.application.services.plan_apply_service import (
        ApplyOutcome,
        ApplyResult,
        PlanApplyService,
    )
    from cleveragents.domain.models.core.change import (
        ChangeEntry,
        ChangeOperation,
        SpecChangeSet,
    )
    from cleveragents.domain.models.core.plan import (
        PlanPhase,
        PlanTimestamps,
        ProcessingState,
    )


_PLAN_ID = "01BENCHPLAN0000000000001"


def _make_plan(
    *,
    changeset_id: str = "CS001",
    validation_summary: dict[str, Any] | None = None,
) -> MagicMock:
    plan = MagicMock()
    plan.identity.plan_id = _PLAN_ID
    plan.phase = PlanPhase.EXECUTE
    plan.processing_state = ProcessingState.COMPLETE
    plan.changeset_id = changeset_id
    plan.validation_summary = validation_summary
    plan.is_terminal = False
    plan.error_details = None
    plan.timestamps = PlanTimestamps()
    return plan


def _make_changeset(n: int = 10) -> SpecChangeSet:
    cs = SpecChangeSet(plan_id=_PLAN_ID)
    for i in range(n):
        cs.add_change(
            ChangeEntry(
                plan_id=_PLAN_ID,
                resource_id="RES001",
                tool_name="builtin/bench-tool",
                operation=ChangeOperation.MODIFY,
                path=f"src/mod_{i:04d}.py",
                before_hash=f"b{i}",
                after_hash=f"a{i}",
            )
        )
    return cs


def _make_service(plan: MagicMock, changeset: SpecChangeSet) -> PlanApplyService:
    lifecycle = MagicMock()
    lifecycle.get_plan.return_value = plan
    lifecycle.complete_apply.return_value = plan
    lifecycle._commit_plan = MagicMock()
    store = MagicMock()
    store.get.return_value = changeset
    return PlanApplyService(lifecycle_service=lifecycle, changeset_store=store)


class ApplyResultSuite:
    """Benchmark ApplyResult model construction."""

    def time_result_construction_applied(self) -> None:
        ApplyResult(
            outcome=ApplyOutcome.APPLIED,
            plan_id=_PLAN_ID,
            message="applied ok",
            files_changed=10,
            validations_total=5,
            validations_passed=5,
            validations_failed=0,
        )

    def time_result_construction_constrained(self) -> None:
        ApplyResult(
            outcome=ApplyOutcome.CONSTRAINED,
            plan_id=_PLAN_ID,
            message="blocked",
            validations_total=5,
            validations_passed=3,
            validations_failed=2,
        )


class ApplyValidationCountSuite:
    """Benchmark validation count extraction."""

    def setup(self) -> None:
        self.summary: dict[str, Any] = {
            "total": 100,
            "required_passed": 80,
            "required_failed": 20,
        }
        self.empty_summary: dict[str, Any] | None = None

    def time_extract_counts(self) -> None:
        PlanApplyService._extract_validation_counts(self.summary)

    def time_extract_counts_none(self) -> None:
        PlanApplyService._extract_validation_counts(self.empty_summary)


class ApplyGateSuite:
    """Benchmark the full apply_with_validation_gate flow."""

    def setup(self) -> None:
        cs = _make_changeset(20)
        self.plan_pass = _make_plan(
            changeset_id=cs.changeset_id,
            validation_summary={
                "total": 5,
                "required_passed": 5,
                "required_failed": 0,
            },
        )
        self.plan_fail = _make_plan(
            changeset_id=cs.changeset_id,
            validation_summary={
                "total": 5,
                "required_passed": 3,
                "required_failed": 2,
            },
        )
        self.svc_pass = _make_service(self.plan_pass, cs)
        self.svc_fail = _make_service(self.plan_fail, cs)

    def time_apply_gate_pass(self) -> None:
        self.svc_pass.apply_with_validation_gate(_PLAN_ID)

    def time_apply_gate_fail(self) -> None:
        self.svc_fail.apply_with_validation_gate(_PLAN_ID)
