"""ASV benchmarks for audit service write throughput.

Measures the overhead of the AuditEventSubscriber pipeline:
EventBus.emit() -> redact_dict() -> AuditService.record() -> SQLite.
"""

from __future__ import annotations

import importlib
import sys
from pathlib import Path
from typing import ClassVar

_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

import cleveragents  # noqa: E402

importlib.reload(cleveragents)

from sqlalchemy import create_engine  # noqa: E402
from sqlalchemy.orm import sessionmaker  # noqa: E402

from cleveragents.application.services.audit_event_subscriber import (  # noqa: E402
    AuditEventSubscriber,
)
from cleveragents.application.services.audit_service import AuditService  # noqa: E402
from cleveragents.config.settings import Settings  # noqa: E402
from cleveragents.infrastructure.database.models import Base  # noqa: E402
from cleveragents.infrastructure.events.models import DomainEvent  # noqa: E402
from cleveragents.infrastructure.events.reactive import (  # noqa: E402
    ReactiveEventBus,
)
from cleveragents.infrastructure.events.types import EventType  # noqa: E402


def _make_audit_service() -> AuditService:
    """Create an in-memory AuditService for benchmarking."""
    Settings._instance = None
    settings = Settings(database_url="sqlite:///:memory:")
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    session = sessionmaker(bind=engine)()
    return AuditService(settings=settings, session=session)


class AuditServiceBenchmarks:
    """Benchmarks for audit event recording throughput."""

    timeout = 120
    params: ClassVar[list[int]] = [1, 10, 100, 1000]
    param_names: ClassVar[list[str]] = ["num_events"]

    def setup(self, num_events: int) -> None:
        # Recreate fresh DB/bus per ASV timing round to prevent row
        # accumulation across repetitions (PERF-4).
        self.svc = _make_audit_service()
        self.bus = ReactiveEventBus()
        self.subscriber = AuditEventSubscriber(
            audit_service=self.svc,
            event_bus=self.bus,
        )
        # Pre-generate unique events so each iteration has a distinct
        # timestamp and correlation_id, avoiding benchmark skew from
        # reusing a single frozen object (PERF-3).
        self.events = [
            DomainEvent(
                event_type=EventType.PLAN_APPLIED,
                plan_id=f"BENCH-{i:04d}",
                details={"action_name": "local/benchmark"},
            )
            for i in range(num_events)
        ]

    def time_record_events(self, num_events: int) -> None:
        for event in self.events:
            self.bus.emit(event)


class AuditDirectRecordBenchmarks:
    """Benchmarks for direct AuditService.record() calls."""

    timeout = 120
    params: ClassVar[list[int]] = [1, 10, 100, 1000]
    param_names: ClassVar[list[str]] = ["num_events"]

    def setup(self, num_events: int) -> None:
        self.svc = _make_audit_service()

    def time_direct_record(self, num_events: int) -> None:
        for _ in range(num_events):
            self.svc.record(
                event_type="plan_applied",
                plan_id="BENCH-001",
                details={"action_name": "local/benchmark"},
            )


class AuditRedactionBenchmarks:
    """Benchmarks for the redaction overhead in audit recording."""

    timeout = 120

    def setup(self) -> None:
        self.svc = _make_audit_service()
        self.bus = ReactiveEventBus()
        self.subscriber = AuditEventSubscriber(
            audit_service=self.svc,
            event_bus=self.bus,
        )
        self.event_with_secrets = DomainEvent(
            event_type=EventType.CONFIG_CHANGED,
            details={
                "api_key": "sk-proj-ABCDEFGHIJ1234567890",
                "token": "tok_ABCDEF1234567890",
                "normal_field": "safe-value",
            },
        )

    def time_record_with_redaction(self) -> None:
        self.bus.emit(self.event_with_secrets)
