"""ASV benchmarks for EventBus infrastructure.

Measures:
- DomainEvent construction throughput
- ReactiveEventBus emit overhead (no subscribers)
- ReactiveEventBus emit with one subscriber
- ReactiveEventBus subscribe registration
- LoggingEventBus emit overhead
- Fan-out: emit to N subscribers
"""

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 cleveragents.infrastructure.events import (  # noqa: E402
    DomainEvent,
    EventType,
    LoggingEventBus,
    ReactiveEventBus,
)

# ---------------------------------------------------------------------------
# DomainEvent construction
# ---------------------------------------------------------------------------


class DomainEventSuite:
    """Benchmark DomainEvent construction overhead."""

    timeout = 60

    def setup(self) -> None:
        self.event_type = EventType.PLAN_CREATED
        self.plan_id = "01ARZ3NDEKTSV4RRFFQ69G5FAV"

    def time_create_minimal(self) -> None:
        DomainEvent(event_type=self.event_type)

    def time_create_with_plan_id(self) -> None:
        DomainEvent(event_type=self.event_type, plan_id=self.plan_id)

    def time_create_with_details(self) -> None:
        DomainEvent(
            event_type=self.event_type,
            plan_id=self.plan_id,
            details={"phase": "strategize", "actor": "strategists/planner"},
        )


# ---------------------------------------------------------------------------
# ReactiveEventBus emit
# ---------------------------------------------------------------------------


class ReactiveEmitSuite:
    """Benchmark ReactiveEventBus.emit() throughput."""

    timeout = 60

    def setup(self) -> None:
        self.bus = ReactiveEventBus()
        self.event = DomainEvent(event_type=EventType.PLAN_CREATED)
        self.decision_event = DomainEvent(event_type=EventType.DECISION_CREATED)

        # Pre-register a subscriber for the with-subscriber benchmarks
        self._received: list[DomainEvent] = []
        self.bus.subscribe(EventType.PLAN_CREATED, self._received.append)

    def time_emit_no_subscribers(self) -> None:
        self.bus.emit(self.decision_event)

    def time_emit_with_one_subscriber(self) -> None:
        self.bus.emit(self.event)

    def time_emit_100_events(self) -> None:
        for _ in range(100):
            self.bus.emit(self.event)


# ---------------------------------------------------------------------------
# ReactiveEventBus subscribe
# ---------------------------------------------------------------------------


class ReactiveSubscribeSuite:
    """Benchmark ReactiveEventBus.subscribe() overhead."""

    timeout = 60

    def setup(self) -> None:
        self.event_type = EventType.PLAN_CREATED

    def time_subscribe_single(self) -> None:
        bus = ReactiveEventBus()
        bus.subscribe(self.event_type, lambda e: None)

    def time_subscribe_10(self) -> None:
        bus = ReactiveEventBus()
        for _ in range(10):
            bus.subscribe(self.event_type, lambda e: None)


# ---------------------------------------------------------------------------
# Fan-out benchmark
# ---------------------------------------------------------------------------


class FanOutSuite:
    """Benchmark event fan-out to multiple subscribers."""

    timeout = 60
    params: ClassVar[list[int]] = [1, 5, 10, 50]
    param_names: ClassVar[list[str]] = ["num_subscribers"]

    def setup(self, num_subscribers: int) -> None:
        self.bus = ReactiveEventBus()
        for _ in range(num_subscribers):
            self.bus.subscribe(EventType.PLAN_CREATED, lambda e: None)
        self.event = DomainEvent(event_type=EventType.PLAN_CREATED)

    def time_emit(self, num_subscribers: int) -> None:
        self.bus.emit(self.event)


# ---------------------------------------------------------------------------
# LoggingEventBus emit
# ---------------------------------------------------------------------------


class LoggingEmitSuite:
    """Benchmark LoggingEventBus.emit() overhead."""

    timeout = 60

    def setup(self) -> None:
        import logging

        logging.disable(logging.CRITICAL)
        self.bus = LoggingEventBus()
        self.event = DomainEvent(event_type=EventType.DECISION_CREATED)

    def time_emit_single(self) -> None:
        self.bus.emit(self.event)

    def time_emit_100(self) -> None:
        for _ in range(100):
            self.bus.emit(self.event)
