"""Airspeed Velocity benchmarks for v3 Plan domain model.

Measures validation, serialization, and as_cli_dict performance for the
Plan model across different field configurations.
"""

from __future__ import annotations

from cleveragents.domain.models.core.plan import (
    AutomationProfileProvenance,
    AutomationProfileRef,
    InvariantSource,
    NamespacedName,
    Plan,
    PlanIdentity,
    PlanInvariant,
    PlanPhase,
    ProcessingState,
    ProjectLink,
    SubplanConfig,
    SubplanStatus,
    can_transition,
)

# Valid ULID constants for benchmarks
_ULID_A = "01HGZ6FE0AQDYTR4BXVQZ6EA00"
_ULID_B = "01HGZ6FE0AQDYTR4BXVQZ6EB00"


def _minimal_plan() -> Plan:
    """Create a minimal Plan with only required fields."""
    return Plan(
        identity=PlanIdentity(plan_id=_ULID_A),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="bench-plan"
        ),
        description="Benchmark plan",
        action_name="local/bench-action",
    )


def _rich_plan() -> Plan:
    """Create a Plan with all optional fields populated."""
    return Plan(
        identity=PlanIdentity(
            plan_id=_ULID_A,
            parent_plan_id=_ULID_B,
            root_plan_id=_ULID_B,
        ),
        namespaced_name=NamespacedName(
            server="prod", namespace="myorg", name="rich-plan"
        ),
        description="Fully populated benchmark plan",
        definition_of_done="All tests pass with >97% coverage",
        action_name="myorg/code-coverage",
        phase=PlanPhase.EXECUTE,
        processing_state=ProcessingState.PROCESSING,
        automation_profile=AutomationProfileRef(
            profile_name="trusted",
            provenance=AutomationProfileProvenance.ACTION,
        ),
        project_links=[
            ProjectLink(project_name="local/api-svc", alias="api", read_only=False),
            ProjectLink(project_name="local/docs", read_only=True),
        ],
        invariants=[
            PlanInvariant(text="No public API changes", source=InvariantSource.ACTION),
            PlanInvariant(text="Keep backward compat", source=InvariantSource.PROJECT),
        ],
        arguments={"target": "src/main.py", "mode": "strict", "verbose": True},
        arguments_order=["target", "mode", "verbose"],
        strategy_actor="local/planner",
        execution_actor="local/coder",
        review_actor="local/reviewer",
        error_message=None,
        subplan_config=SubplanConfig(max_parallel=3),
        subplan_statuses=[
            SubplanStatus(subplan_id=_ULID_B, action_name="local/sub-action"),
        ],
    )


class PlanValidationSuite:
    """Benchmark Plan model validation (construction)."""

    def time_minimal_plan_creation(self) -> None:
        """Time creating a minimal Plan with only required fields."""
        _minimal_plan()

    def time_rich_plan_creation(self) -> None:
        """Time creating a Plan with all optional fields populated."""
        _rich_plan()

    def time_plan_model_validate_dict(self) -> None:
        """Time Plan.model_validate from a raw dict."""
        Plan.model_validate(
            {
                "identity": {"plan_id": _ULID_A},
                "namespaced_name": {"namespace": "local", "name": "bench-plan"},
                "description": "Benchmark plan",
                "action_name": "local/bench-action",
            }
        )


class PlanSerializationSuite:
    """Benchmark Plan model serialization."""

    def setup(self) -> None:
        self.minimal = _minimal_plan()
        self.rich = _rich_plan()

    def time_minimal_model_dump(self) -> None:
        """Time model_dump for a minimal Plan."""
        self.minimal.model_dump()

    def time_rich_model_dump(self) -> None:
        """Time model_dump for a fully populated Plan."""
        self.rich.model_dump()

    def time_minimal_model_dump_json(self) -> None:
        """Time model_dump_json for a minimal Plan."""
        self.minimal.model_dump_json()

    def time_rich_model_dump_json(self) -> None:
        """Time model_dump_json for a fully populated Plan."""
        self.rich.model_dump_json()


class PlanCliDictSuite:
    """Benchmark Plan.as_cli_dict output generation."""

    def setup(self) -> None:
        self.minimal = _minimal_plan()
        self.rich = _rich_plan()

    def time_minimal_as_cli_dict(self) -> None:
        """Time as_cli_dict for a minimal Plan."""
        self.minimal.as_cli_dict()

    def time_rich_as_cli_dict(self) -> None:
        """Time as_cli_dict for a Plan with all optional fields."""
        self.rich.as_cli_dict()


class PhaseTransitionSuite:
    """Benchmark phase transition validation."""

    def time_can_transition_valid(self) -> None:
        """Time a valid phase transition check."""
        can_transition(PlanPhase.STRATEGIZE, PlanPhase.EXECUTE)

    def time_can_transition_invalid(self) -> None:
        """Time an invalid phase transition check."""
        can_transition(PlanPhase.STRATEGIZE, PlanPhase.APPLY)

    def time_all_transitions(self) -> None:
        """Time checking all possible phase transition pairs."""
        for from_phase in PlanPhase:
            for to_phase in PlanPhase:
                can_transition(from_phase, to_phase)


class NamespacedNameSuite:
    """Benchmark NamespacedName parsing and serialization."""

    def time_parse_simple(self) -> None:
        """Time parsing a simple name."""
        NamespacedName.parse("my-action")

    def time_parse_full(self) -> None:
        """Time parsing a full server:namespace/name string."""
        NamespacedName.parse("prod:myorg/my-action")

    def time_str_representation(self) -> None:
        """Time string representation of a NamespacedName."""
        name = NamespacedName(server="prod", namespace="myorg", name="my-action")
        str(name)
