"""ASV benchmarks for project context CLI command overhead.

Measures the cost of:
- Reading a context policy from the DB
- Writing a context policy to the DB
- Policy serialization round-trip for CLI output
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Any

try:
    from cleveragents.domain.models.core.context_policy import (
        ContextView,
        ProjectContextPolicy,
    )
    from cleveragents.domain.models.core.project import (
        NamespacedProject,
        parse_namespaced_name,
    )
    from cleveragents.infrastructure.database.models import Base
    from cleveragents.infrastructure.database.repositories import (
        NamespacedProjectRepository,
    )
except ModuleNotFoundError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
    from cleveragents.domain.models.core.context_policy import (
        ContextView,
        ProjectContextPolicy,
    )
    from cleveragents.domain.models.core.project import (
        NamespacedProject,
        parse_namespaced_name,
    )
    from cleveragents.infrastructure.database.models import Base
    from cleveragents.infrastructure.database.repositories import (
        NamespacedProjectRepository,
    )

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker


class _NoCloseSession:
    """Session wrapper that no-ops close()."""

    def __init__(self, real: object) -> None:
        object.__setattr__(self, "_real", real)

    def close(self) -> None:
        pass

    def __getattr__(self, name: str) -> Any:
        return getattr(object.__getattribute__(self, "_real"), name)


def _make_repo_and_factory() -> tuple[NamespacedProjectRepository, Any]:
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    sess = sessionmaker(bind=engine, expire_on_commit=False)()
    wrapper = _NoCloseSession(sess)

    def factory() -> Any:
        return wrapper

    repo = NamespacedProjectRepository(session_factory=factory)
    return repo, factory


def _make_policy() -> ProjectContextPolicy:
    return ProjectContextPolicy(
        default_view=ContextView(
            include_resources=["db-*"],
            exclude_resources=["db-test"],
            include_paths=["src/**"],
            exclude_paths=["*.pyc"],
            max_file_size=1048576,
            max_total_size=10485760,
        ),
        strategize_view=ContextView(
            include_resources=["db-*", "cache-*"],
        ),
        execute_view=ContextView(
            include_paths=["src/**", "lib/**"],
        ),
    )


class ContextPolicyReadWriteSuite:
    """Benchmark policy read/write to DB."""

    timeout = 30.0

    def setup(self) -> None:
        from cleveragents.cli.commands.project_context import (
            _write_policy,
        )

        self.repo, self.sf = _make_repo_and_factory()
        parsed = parse_namespaced_name("bench-ctx")
        proj = NamespacedProject(
            name=parsed.name,
            namespace=parsed.namespace,
        )
        self.repo.create(proj)
        _write_policy(self.sf, "local/bench-ctx", _make_policy())

    def time_read_policy(self) -> None:
        from cleveragents.cli.commands.project_context import (
            _read_policy,
        )

        _read_policy(self.sf, "local/bench-ctx")

    def time_write_policy(self) -> None:
        from cleveragents.cli.commands.project_context import (
            _write_policy,
        )

        _write_policy(self.sf, "local/bench-ctx", _make_policy())


class ContextPolicySerializeSuite:
    """Benchmark policy serialization for CLI output."""

    timeout = 30.0

    def setup(self) -> None:
        self.policy = _make_policy()

    def time_model_dump(self) -> None:
        self.policy.model_dump(mode="json")

    def time_model_dump_json(self) -> None:
        self.policy.model_dump_json()

    def time_json_roundtrip(self) -> None:
        blob = self.policy.model_dump_json()
        ProjectContextPolicy.model_validate_json(blob)

    def time_resolve_and_dump(self) -> None:
        for phase in [
            "default",
            "strategize",
            "execute",
            "apply",
        ]:
            v = self.policy.resolve_view(phase)
            v.model_dump(mode="json")
