"""ASV benchmarks for project create + list persistence round-trip.

Measures the cost of creating a project and then listing it back via the
``NamespacedProjectRepository``, using a file-based SQLite database so
that each operation gets a fresh session (matching real CLI behaviour).

Targets bug #589 — ``create()`` now calls ``session.commit()`` so data
is visible to a subsequent ``list()`` in a separate session.
"""

from __future__ import annotations

import importlib
import os
import shutil
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 sqlalchemy import create_engine  # noqa: E402
from sqlalchemy.orm import sessionmaker  # noqa: E402
from sqlalchemy.pool import NullPool  # noqa: E402

from cleveragents.domain.models.core.project import (  # noqa: E402
    NamespacedProject,
    parse_namespaced_name,
)
from cleveragents.infrastructure.database.models import Base  # noqa: E402
from cleveragents.infrastructure.database.repositories import (  # noqa: E402
    NamespacedProjectRepository,
)


def _fresh_repo(db_path: str) -> NamespacedProjectRepository:
    """Return a repo backed by a *new* engine/session for *db_path*.

    ``NullPool`` ensures SQLite file handles are released immediately
    when the engine is no longer referenced.
    """
    engine = create_engine(f"sqlite:///{db_path}", echo=False, poolclass=NullPool)
    Base.metadata.create_all(engine)
    factory = sessionmaker(bind=engine, expire_on_commit=False)
    return NamespacedProjectRepository(session_factory=factory)


class ProjectPersistRoundTripSuite:
    """Benchmark create-then-list round trip with separate sessions."""

    timeout = 30.0

    def setup(self) -> None:
        self._tmpdir = tempfile.mkdtemp(prefix="bench_persist_589_")
        self._db_path = os.path.join(self._tmpdir, "bench.db")
        # Initialise schema once.
        engine = create_engine(
            f"sqlite:///{self._db_path}",
            echo=False,
            poolclass=NullPool,
        )
        Base.metadata.create_all(engine)
        engine.dispose()
        self._counter = 0

    def teardown(self) -> None:
        shutil.rmtree(self._tmpdir, ignore_errors=True)

    def time_create_then_list(self) -> None:
        """Create a project in one session, list in another."""
        self._counter += 1
        name = f"bench-{self._counter}"
        parsed = parse_namespaced_name(name)
        proj = NamespacedProject(name=parsed.name, namespace=parsed.namespace)

        create_repo = _fresh_repo(self._db_path)
        create_repo.create(proj)

        list_repo = _fresh_repo(self._db_path)
        list_repo.list_projects()

    def track_list_after_create_count(self) -> int:
        """Track whether list sees the created project.

        Returns the number of projects visible after create + commit.
        Expected value is 1 (or more if called repeatedly).
        """
        self._counter += 1
        name = f"bench-track-{self._counter}"
        parsed = parse_namespaced_name(name)
        proj = NamespacedProject(name=parsed.name, namespace=parsed.namespace)

        create_repo = _fresh_repo(self._db_path)
        create_repo.create(proj)

        list_repo = _fresh_repo(self._db_path)
        projects = list_repo.list_projects()
        return len(projects)


ProjectPersistRoundTripSuite.track_list_after_create_count.unit = "projects"  # type: ignore[attr-defined]
