"""ASV benchmarks for Tool Registry persistence operations.

Measures the performance of:
- ToolModel.from_domain() construction
- ToolModel.to_domain() reconstruction
- ToolRegistryRepository CRUD operations (in-memory SQLite)
- ValidationAttachmentRepository attach/list operations
"""

from __future__ import annotations

import sys
from datetime import datetime
from pathlib import Path

try:
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    from cleveragents.infrastructure.database.models import Base, ToolModel
    from cleveragents.infrastructure.database.repositories import (
        ToolRegistryRepository,
        ValidationAttachmentRepository,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    from cleveragents.infrastructure.database.models import Base, ToolModel
    from cleveragents.infrastructure.database.repositories import (
        ToolRegistryRepository,
        ValidationAttachmentRepository,
    )


def _make_tool_dict(
    name: str = "bench/tool-test",
    source: str = "builtin",
    tool_type: str = "tool",
) -> dict[str, object]:
    """Create a minimal tool dict for benchmarks."""
    now = datetime.now().isoformat()
    return {
        "name": name,
        "description": f"Benchmark tool {name}",
        "tool_type": tool_type,
        "source": source,
        "timeout": 300,
        "created_at": now,
        "updated_at": now,
        "resource_bindings": [
            {
                "slot_name": "repo",
                "resource_type": "git-checkout",
                "access_mode": "read_only",
                "binding_mode": "contextual",
                "required": True,
            },
        ],
    }


def _setup_db():
    """Create in-memory DB and return (session, tool_repo, att_repo)."""
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    factory = sessionmaker(bind=engine, expire_on_commit=False)
    session = factory()
    tool_repo = ToolRegistryRepository(session_factory=lambda: session)
    att_repo = ValidationAttachmentRepository(session_factory=lambda: session)
    return session, tool_repo, att_repo


class ToolModelSuite:
    """Benchmark ToolModel ORM construction and conversion."""

    def setup(self) -> None:
        """Prepare objects."""
        self.tool_dict = _make_tool_dict()

    def time_from_domain(self) -> None:
        """Benchmark ToolModel.from_domain() construction."""
        ToolModel.from_domain(self.tool_dict)

    def time_to_domain(self) -> None:
        """Benchmark ToolModel.to_domain() conversion."""
        model = ToolModel.from_domain(self.tool_dict)
        model.resource_bindings_rel = []
        model.to_domain()


class ToolRegistryCRUDSuite:
    """Benchmark ToolRegistryRepository CRUD operations."""

    def setup(self) -> None:
        """Prepare a fresh in-memory database for each benchmark."""
        self.session, self.repo, self.att_repo = _setup_db()
        self._counter = 0

    def time_create_tool(self) -> None:
        """Benchmark creating a single tool."""
        self._counter += 1
        tool = _make_tool_dict(name=f"bench/tool-{self._counter}")
        self.repo.create(tool)
        self.session.commit()

    def time_get_by_name(self) -> None:
        """Benchmark retrieving a tool by name."""
        name = "bench/lookup-target"
        if self.repo.get_by_name(name) is None:
            self.repo.create(_make_tool_dict(name=name))
            self.session.commit()
        self.repo.get_by_name(name)

    def time_list_all(self) -> None:
        """Benchmark listing all tools."""
        # Ensure some data exists
        for i in range(5):
            n = f"bench/list-{i}"
            if self.repo.get_by_name(n) is None:
                self.repo.create(_make_tool_dict(name=n))
        self.session.commit()
        self.repo.list_all()


class ValidationAttachmentSuite:
    """Benchmark ValidationAttachmentRepository operations."""

    def setup(self) -> None:
        """Prepare database with a validation tool."""
        self.session, self.repo, self.att_repo = _setup_db()
        val = _make_tool_dict(
            name="bench/val-bench",
            tool_type="validation",
        )
        val["mode"] = "required"
        self.repo.create(val)
        self.session.commit()
        self._counter = 0

    def time_attach(self) -> None:
        """Benchmark attaching a validation."""
        self._counter += 1
        self.att_repo.attach(
            validation_name="bench/val-bench",
            resource_id=f"res-{self._counter}",
            mode="required",
        )
        self.session.commit()

    def time_list_for_resource(self) -> None:
        """Benchmark listing attachments for a resource."""
        res_id = "res-bench-list"
        if not self.att_repo.list_for_resource(res_id):
            self.att_repo.attach(
                validation_name="bench/val-bench",
                resource_id=res_id,
                mode="required",
            )
            self.session.commit()
        self.att_repo.list_for_resource(res_id)
