from __future__ import annotations

"""Pluggable event bus for orchestration observability."""

import asyncio
from dataclasses import dataclass
from typing import Any, AsyncIterator, Protocol

from agentrspy.core import AgentOutput


@dataclass(slots=True)
class OrchestratorEvent:
    """Event emitted during orchestration."""

    agent: str
    output: AgentOutput


class EventBus(Protocol):
    """Event bus contract."""

    async def publish(self, event: OrchestratorEvent) -> None:
        """Publish an event."""

    async def subscribe(self) -> AsyncIterator[OrchestratorEvent]:
        """Subscribe to future events."""


class InMemoryBus:
    """In-memory broadcast event bus."""

    def __init__(self, capacity: int) -> None:
        self.capacity = capacity
        self.subscribers: list[asyncio.Queue[OrchestratorEvent]] = []

    @classmethod
    def new(cls, capacity: int) -> "InMemoryBus":
        return cls(capacity)

    async def publish(self, event: OrchestratorEvent) -> None:
        for queue in list(self.subscribers):
            if queue.full():
                try:
                    queue.get_nowait()
                except asyncio.QueueEmpty:
                    pass
            await queue.put(event)

    async def subscribe(self) -> AsyncIterator[OrchestratorEvent]:
        queue: asyncio.Queue[OrchestratorEvent] = asyncio.Queue(maxsize=self.capacity)
        self.subscribers.append(queue)

        async def iterator() -> AsyncIterator[OrchestratorEvent]:
            try:
                while True:
                    yield await queue.get()
            finally:
                self.subscribers.remove(queue)

        return iterator()
