"""ASV benchmarks for SEC7 - Audit logging overhead.

Measures the performance of recording, querying, and pruning
audit log entries to establish baselines for write overhead.
"""

from __future__ import annotations

from datetime import UTC, datetime, timedelta

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from cleveragents.application.services.audit_service import _TIMESTAMP_FMT, AuditService
from cleveragents.config.settings import Settings
from cleveragents.infrastructure.database.models import AuditLogModel, Base


def _make_service() -> AuditService:
    """Create a service backed by in-memory SQLite."""
    Settings._instance = None
    settings = Settings()
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    session = sessionmaker(bind=engine)()
    return AuditService(settings=settings, session=session)


def _seed_entries(service: AuditService, count: int) -> None:
    """Insert *count* entries for benchmarking."""
    for i in range(count):
        service.record(
            event_type="plan_applied",
            plan_id=f"plan-{i}",
            project_name="bench-project",
            details={"index": i},
        )


class TimeRecordSingle:
    """Benchmark recording a single audit event."""

    timeout = 30

    def setup(self) -> None:
        self.service = _make_service()

    def teardown(self) -> None:
        pass

    def time_record_single_event(self) -> None:
        self.service.record(
            event_type="plan_applied",
            plan_id="bench-plan",
            project_name="bench-project",
            details={"files_changed": 5},
        )


class TimeRecordBatch:
    """Benchmark recording a batch of audit events."""

    timeout = 60

    def setup(self) -> None:
        self.service = _make_service()

    def teardown(self) -> None:
        pass

    def time_record_100_events(self) -> None:
        for i in range(100):
            self.service.record(
                event_type="plan_applied",
                plan_id=f"plan-{i}",
                details={"index": i},
            )


class TimeQueryEntries:
    """Benchmark querying audit log entries."""

    timeout = 30

    def setup(self) -> None:
        self.service = _make_service()
        _seed_entries(self.service, 500)

    def teardown(self) -> None:
        pass

    def time_list_all(self) -> None:
        self.service.list_entries(limit=100)

    def time_list_by_plan(self) -> None:
        self.service.list_entries(plan_id="plan-42")

    def time_list_by_project(self) -> None:
        self.service.list_entries(project_name="bench-project")

    def time_list_by_type(self) -> None:
        self.service.list_entries(event_type="plan_applied")

    def time_get_single(self) -> None:
        self.service.get_entry(250)

    def time_count(self) -> None:
        self.service.count()


class TimePrune:
    """Benchmark pruning old audit entries.

    Uses ``setup`` to re-seed 200 backdated entries before *each*
    benchmark iteration so that every call to ``prune()`` actually
    deletes rows (ASV calls ``time_*`` multiple times per ``setup``
    by default).
    """

    timeout = 30
    # ASV calls setup() before each iteration when number=1.
    number = 1

    def setup(self) -> None:
        self.service = _make_service()
        # Insert entries backdated to 60 days ago
        old_time = (datetime.now(tz=UTC) - timedelta(days=60)).strftime(_TIMESTAMP_FMT)
        for i in range(200):
            row = AuditLogModel(
                event_type="plan_applied",
                plan_id=f"plan-{i}",
                details="{}",
                created_at=old_time,
            )
            self.service._session.add(row)
        self.service._session.commit()

    def teardown(self) -> None:
        pass

    def time_prune_200_entries(self) -> None:
        self.service.prune(retention_days=30)
