"""ASV benchmarks for custom sandbox strategy registration.

Measures the performance of:
- SandboxRef creation
- DiffView / DiffEntry model creation
- SandboxStrategyRegistry registration and lookup
- BuiltInSandboxStrategyAdapter create/write/read cycle
- Protocol runtime checking via isinstance
"""

from __future__ import annotations

import importlib
import os
import sys
import tempfile
from datetime import datetime
from pathlib import Path

# Ensure the local *source* tree is importable even when ASV has an
# older build of the package installed.
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

# Force-reload so ASV picks up the source tree version.
import cleveragents  # noqa: E402

importlib.reload(cleveragents)

from cleveragents.domain.models.core.resource import (  # noqa: E402
    PhysVirt,
    Resource,
    ResourceCapabilities,
)
from cleveragents.domain.models.core.resource import (  # noqa: E402
    SandboxStrategy as SandboxStrategyEnum,
)
from cleveragents.domain.models.core.sandbox_strategy import (  # noqa: E402
    DiffEntry,
    DiffView,
    SandboxRef,
    SandboxStrategyProtocol,
)
from cleveragents.infrastructure.sandbox.strategy_adapter import (  # noqa: E402
    BuiltInSandboxStrategyAdapter,
)
from cleveragents.infrastructure.sandbox.strategy_registry import (  # noqa: E402
    SandboxStrategyRegistry,
)

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

_COUNTER = 0


def _ulid(name: str) -> str:
    global _COUNTER
    _COUNTER += 1
    base = abs(hash(name)) % (10**20)
    raw = f"{_COUNTER:06d}{base:020d}"
    charset = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
    result = ""
    for ch in raw:
        result += charset[int(ch)]
    return (result + "0" * 26)[:26]


class _MockStrategy:
    """Minimal strategy satisfying the Protocol for benchmarking."""

    def create(self, plan_id, resource):
        return None

    def read(self, ref, path):
        return b""

    def write(self, ref, path, content):
        return None

    def diff(self, ref):
        return None

    def commit(self, ref):
        pass

    def rollback(self, ref):
        pass

    def checkpoint(self, ref, checkpoint_id):
        pass

    def restore_checkpoint(self, ref, checkpoint_id):
        pass

    def cleanup(self, ref):
        pass


# ---------------------------------------------------------------------------
# SandboxRef benchmarks
# ---------------------------------------------------------------------------


class TimeSandboxRef:
    """Benchmark SandboxRef creation."""

    def time_create_ref(self) -> None:
        SandboxRef(
            sandbox_id="bench-ref",
            plan_id="bench-plan",
            resource_id="bench-res",
            created_at=datetime.now(),
        )

    def time_create_ref_with_metadata(self) -> None:
        SandboxRef(
            sandbox_id="bench-ref-meta",
            plan_id="bench-plan",
            resource_id="bench-res",
            created_at=datetime.now(),
            metadata={"key": "value", "num": 42},
        )


# ---------------------------------------------------------------------------
# DiffEntry / DiffView benchmarks
# ---------------------------------------------------------------------------


class TimeDiffModels:
    """Benchmark DiffEntry and DiffView creation."""

    def time_create_diff_entry(self) -> None:
        DiffEntry(path="bench.txt", operation="modified")

    def time_create_diff_entry_with_content(self) -> None:
        DiffEntry(
            path="bench.txt",
            operation="modified",
            before=b"old",
            after=b"new",
        )

    def time_create_diff_view_10_entries(self) -> None:
        entries = [
            DiffEntry(path=f"file{i}.txt", operation="modified") for i in range(10)
        ]
        DiffView(sandbox_id="bench-dv", entries=entries)


# ---------------------------------------------------------------------------
# Protocol checking benchmarks
# ---------------------------------------------------------------------------


class TimeProtocolCheck:
    """Benchmark SandboxStrategyProtocol isinstance checks."""

    def setup(self) -> None:
        self.good = _MockStrategy()

    def time_isinstance_check_pass(self) -> None:
        isinstance(self.good, SandboxStrategyProtocol)

    def time_isinstance_check_fail(self) -> None:
        isinstance("not a strategy", SandboxStrategyProtocol)


# ---------------------------------------------------------------------------
# SandboxStrategyRegistry benchmarks
# ---------------------------------------------------------------------------


class TimeStrategyRegistry:
    """Benchmark registry operations."""

    def setup(self) -> None:
        self.registry = SandboxStrategyRegistry(
            allowed_prefixes=("cleveragents.",),
        )
        self.registry.register(
            "bench_adapter",
            "cleveragents.infrastructure.sandbox.strategy_adapter",
            "BuiltInSandboxStrategyAdapter",
        )

    def time_lookup_hit(self) -> None:
        self.registry.get("bench_adapter")

    def time_lookup_miss(self) -> None:
        self.registry.get("nonexistent")

    def time_has_check(self) -> None:
        self.registry.has("bench_adapter")

    def time_list_strategies(self) -> None:
        self.registry.list_strategies()


# ---------------------------------------------------------------------------
# BuiltInSandboxStrategyAdapter benchmarks
# ---------------------------------------------------------------------------


class TimeAdapterLifecycle:
    """Benchmark adapter create/write/read cycle."""

    def setup(self) -> None:
        self.tmpdir = tempfile.mkdtemp(prefix="ca-bench-adapter-")
        with open(os.path.join(self.tmpdir, "seed.txt"), "w") as f:
            f.write("seed")
        self.adapter = BuiltInSandboxStrategyAdapter(strategy_name="copy_on_write")
        self.resource = Resource(
            resource_id=_ulid("bench-adapter"),
            name="bench-adapter",
            resource_type_name="fs-directory",
            classification=PhysVirt.PHYSICAL,
            sandbox_strategy=SandboxStrategyEnum.COPY_ON_WRITE,
            location=self.tmpdir,
            capabilities=ResourceCapabilities(
                readable=True,
                writable=True,
                sandboxable=True,
                checkpointable=False,
            ),
        )

    def time_create_and_cleanup(self) -> None:
        ref = self.adapter.create("bench-plan", self.resource)
        self.adapter.cleanup(ref)

    def time_write_read_cycle(self) -> None:
        ref = self.adapter.create("bench-plan-wr", self.resource)
        self.adapter.write(ref, "bench.txt", b"bench content")
        self.adapter.read(ref, "bench.txt")
        self.adapter.cleanup(ref)

    def teardown(self) -> None:
        import shutil

        shutil.rmtree(self.tmpdir, ignore_errors=True)
