"""ASV benchmarks for devcontainer lifecycle activation latency.

Measures the performance of:
- ContainerLifecycleState transition validation
- Lifecycle tracker construction and transition
- Lazy activation with mock runner (no real subprocess)
- JSON output parsing from devcontainer up
- Lifecycle registry operations (get/set/list)

Based on issue #514: Devcontainer lifecycle management.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path
from typing import ClassVar

try:
    from cleveragents.domain.models.core.container_lifecycle import (
        ContainerLifecycleState,
        ContainerLifecycleTracker,
        transition_state,
        validate_transition,
    )
    from cleveragents.resource.handlers.devcontainer import (
        _parse_devcontainer_up_output,
        activate_container,
        clear_lifecycle_registry,
        get_lifecycle_tracker,
        list_active_containers,
        set_lifecycle_tracker,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.domain.models.core.container_lifecycle import (
        ContainerLifecycleState,
        ContainerLifecycleTracker,
        transition_state,
        validate_transition,
    )
    from cleveragents.resource.handlers.devcontainer import (
        _parse_devcontainer_up_output,
        activate_container,
        clear_lifecycle_registry,
        get_lifecycle_tracker,
        list_active_containers,
        set_lifecycle_tracker,
    )


class _MockResult:
    """Minimal mock result for benchmark subprocess calls."""

    def __init__(self) -> None:
        self.returncode = 0
        self.stdout = json.dumps(
            {
                "outcome": "success",
                # F3 fix: use valid 20-char hex ID to pass S1 validation
                "containerId": "aabbccddee0011223344",
                "remoteWorkspaceFolder": "/ws",
            }
        )
        self.stderr = ""


def _mock_runner(args: list[str], **kwargs: object) -> _MockResult:
    """Zero-overhead mock subprocess runner."""
    return _MockResult()


class TimeTransitionValidation:
    """Benchmark validate_transition throughput."""

    timeout = 10

    def time_valid_transition(self) -> None:
        """Time valid transition check (1000 iterations)."""
        for _ in range(1000):
            validate_transition(
                ContainerLifecycleState.DETECTED,
                ContainerLifecycleState.BUILDING,
            )

    def time_invalid_transition(self) -> None:
        """Time invalid transition check (1000 iterations)."""
        for _ in range(1000):
            validate_transition(
                ContainerLifecycleState.DETECTED,
                ContainerLifecycleState.RUNNING,
            )


class TimeTrackerConstruction:
    """Benchmark lifecycle tracker creation."""

    timeout = 10

    def time_tracker_construction(self) -> None:
        """Time ContainerLifecycleTracker instantiation."""
        for i in range(1000):
            ContainerLifecycleTracker(
                resource_id=f"01BENCH{i:020d}",
            )


class TimeTransitionState:
    """Benchmark state transition with history recording."""

    timeout = 30

    def time_single_transition(self) -> None:
        """Time a single state transition."""
        for _ in range(1000):
            tracker = ContainerLifecycleTracker(
                resource_id="01BENCHTRACKER0000000001",
            )
            transition_state(
                tracker,
                ContainerLifecycleState.BUILDING,
                reason="benchmark",
            )


class TimeActivationLatency:
    """Benchmark lazy activation with mock runner."""

    timeout = 30
    params: ClassVar[list[int]] = [1, 10, 50]
    param_names: ClassVar[list[str]] = ["num_activations"]

    def setup(self, num_activations: int) -> None:
        """Clear registry before each timing iteration (R17 fix).

        Without this, trackers from prior iterations accumulate in
        ``_lifecycle_registry`` and subsequent activate calls fail
        with invalid-transition errors (``running`` → ``building``).
        """
        clear_lifecycle_registry()

    def time_activation(self, num_activations: int) -> None:
        """Time container activation with mock runner.

        R8-F6 fix: clear the registry after the loop to stop health
        check threads spawned by each activation (F3 auto-start).
        Without this, ``num_activations`` daemon threads accumulate
        during the timing call.
        """
        for i in range(num_activations):
            activate_container(
                f"01BENCHACTIVATE{i:011d}",
                "/workspace",
                run_command=_mock_runner,
            )
        clear_lifecycle_registry()

    def teardown(self, num_activations: int) -> None:
        """Clear registry after each timing iteration (safety net)."""
        clear_lifecycle_registry()


class TimeJsonParsing:
    """Benchmark devcontainer up JSON output parsing."""

    timeout = 10

    def setup(self) -> None:
        """Create sample JSON output."""
        self.valid_json = json.dumps(
            {
                "outcome": "success",
                "containerId": "aabbccddee0011223344",
                "remoteWorkspaceFolder": "/workspaces/project",
            }
        )
        self.invalid_json = "not valid json {{"

    def time_parse_valid_json(self) -> None:
        """Time parsing valid JSON output."""
        for _ in range(1000):
            _parse_devcontainer_up_output(self.valid_json)

    def time_parse_invalid_json(self) -> None:
        """Time parsing invalid JSON output."""
        for _ in range(1000):
            _parse_devcontainer_up_output(self.invalid_json)


class TimeRegistryOperations:
    """Benchmark lifecycle registry get/set/list operations."""

    timeout = 30

    def setup(self) -> None:
        """Pre-populate registry with trackers."""
        clear_lifecycle_registry()
        for i in range(100):
            tracker = ContainerLifecycleTracker(
                resource_id=f"01BENCHREG{i:016d}",
                current_state=ContainerLifecycleState.RUNNING
                if i % 2 == 0
                else ContainerLifecycleState.DETECTED,
            )
            set_lifecycle_tracker(tracker)

    def teardown(self) -> None:
        """Clear registry."""
        clear_lifecycle_registry()

    def time_get_tracker(self) -> None:
        """Time registry lookup."""
        for i in range(1000):
            get_lifecycle_tracker(f"01BENCHREG{(i % 100):016d}")

    def time_list_active(self) -> None:
        """Time listing active containers."""
        for _ in range(100):
            list_active_containers()
