"""ASV benchmarks for database resource types and transaction sandbox.

Measures the performance of:
- Database type definition lookup
- Connection argument resolution
- Connection validation (SQLite)
- TransactionSandbox create/commit/rollback lifecycle
- SandboxFactory routing for transaction_rollback
"""

from __future__ import annotations

import importlib
import os
import sqlite3
import sys
import tempfile
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.infrastructure.sandbox.factory import (  # noqa: E402
    SandboxFactory,
)
from cleveragents.infrastructure.sandbox.transaction_sandbox import (  # noqa: E402
    TransactionSandbox,
)
from cleveragents.resource.handlers.database import (  # noqa: E402
    DATABASE_TYPE_DEFS,
    DatabaseResourceHandler,
    resolve_connection_args,
    validate_connection,
)

# ---------------------------------------------------------------------------
# Type definition benchmarks
# ---------------------------------------------------------------------------


class TypeDefinitionSuite:
    """Benchmark database type definition operations."""

    timeout = 60

    def time_lookup_all_type_defs(self) -> None:
        """Time iterating all database type definitions."""
        for td in DATABASE_TYPE_DEFS:
            _ = td["name"]

    def time_resolve_postgres_args(self) -> None:
        """Time resolving postgres connection args."""
        resolve_connection_args(
            {"host": "db.example.com", "port": 5432, "dbname": "mydb"},
            "postgres",
        )

    def time_resolve_sqlite_args(self) -> None:
        """Time resolving sqlite connection args."""
        resolve_connection_args({"path": "/tmp/test.db"}, "sqlite")

    def time_handler_instantiation(self) -> None:
        """Time creating a DatabaseResourceHandler."""
        DatabaseResourceHandler()


# ---------------------------------------------------------------------------
# Connection validation benchmarks
# ---------------------------------------------------------------------------


class ConnectionValidationSuite:
    """Benchmark connection validation operations."""

    timeout = 60

    def setup(self) -> None:
        """Create a temp SQLite database for benchmarking."""
        fd, self.db_path = tempfile.mkstemp(suffix=".db")
        os.close(fd)
        conn = sqlite3.connect(self.db_path)
        conn.execute("CREATE TABLE bench (id INTEGER PRIMARY KEY)")
        conn.commit()
        conn.close()

    def teardown(self) -> None:
        """Remove the temp database."""
        if hasattr(self, "db_path") and os.path.exists(self.db_path):
            os.unlink(self.db_path)

    def time_validate_sqlite_file(self) -> None:
        """Time validating a file-based SQLite connection."""
        validate_connection("sqlite", {"path": self.db_path})

    def time_validate_sqlite_memory(self) -> None:
        """Time validating an in-memory SQLite connection."""
        validate_connection("sqlite", {"path": ":memory:"})

    def time_validate_postgres_stub(self) -> None:
        """Time validating a postgres stub (no driver)."""
        validate_connection(
            "postgres",
            {"host": "localhost", "port": 5432, "dbname": "bench"},
        )


# ---------------------------------------------------------------------------
# Transaction sandbox benchmarks
# ---------------------------------------------------------------------------


class TransactionSandboxSuite:
    """Benchmark TransactionSandbox lifecycle operations."""

    timeout = 60

    def setup(self) -> None:
        """Create a temp SQLite database for benchmarking."""
        fd, self.db_path = tempfile.mkstemp(suffix=".db")
        os.close(fd)
        conn = sqlite3.connect(self.db_path)
        conn.execute("CREATE TABLE bench (id INTEGER PRIMARY KEY, val TEXT)")
        conn.commit()
        conn.close()

    def teardown(self) -> None:
        """Remove the temp database."""
        if hasattr(self, "db_path") and os.path.exists(self.db_path):
            os.unlink(self.db_path)

    def time_create_and_cleanup(self) -> None:
        """Time sandbox create + cleanup cycle."""
        sandbox = TransactionSandbox(resource_id="bench-1", original_path=self.db_path)
        sandbox.create(plan_id="BENCH-PLAN")
        sandbox.cleanup()

    def time_create_insert_commit(self) -> None:
        """Time full sandbox lifecycle: create, insert, commit, cleanup."""
        sandbox = TransactionSandbox(resource_id="bench-2", original_path=self.db_path)
        sandbox.create(plan_id="BENCH-PLAN")
        sandbox.execute("INSERT INTO bench (id, val) VALUES (1, 'bench')")
        sandbox.commit("bench commit")
        sandbox.cleanup()

    def time_create_insert_rollback(self) -> None:
        """Time sandbox lifecycle with rollback."""
        sandbox = TransactionSandbox(resource_id="bench-3", original_path=self.db_path)
        sandbox.create(plan_id="BENCH-PLAN")
        sandbox.execute("INSERT INTO bench (id, val) VALUES (2, 'rollback')")
        sandbox.rollback()
        sandbox.cleanup()


# ---------------------------------------------------------------------------
# Factory routing benchmarks
# ---------------------------------------------------------------------------


class FactoryRoutingSuite:
    """Benchmark SandboxFactory routing for database strategies."""

    timeout = 60

    def time_factory_transaction_rollback(self) -> None:
        """Time factory creating a TransactionSandbox."""
        factory = SandboxFactory()
        factory.create_sandbox(
            resource_id="bench-factory",
            original_path=":memory:",
            sandbox_strategy="transaction_rollback",
        )
