"""Event dispatcher for registering callbacks on stream events."""

from __future__ import annotations

from typing import Any, Callable, Optional, Union

from sd_api.models.quote import Quote, QuoteSnapshot
from sd_api.logging import get_logger

logger = get_logger("stream.dispatcher")


class Dispatcher:
    """Event dispatcher that routes stream data to registered callbacks.

    Supports two registration styles::

        # 1. Decorator
        dispatcher = Dispatcher()
        @dispatcher.on_quote
        def handle(q):
            print(q.symbol, q.bid, q.ask)

        # 2. Manual
        dispatcher.on_snapshot(my_handler)

    Then pass the dispatcher to SDStream::

        for _ in stream.quotes(callback=dispatcher):
            pass
    """

    def __init__(self) -> None:
        self._quote_handlers: list[Callable[[Quote], Any]] = []
        self._snapshot_handlers: list[Callable[[QuoteSnapshot], Any]] = []
        self._error_handlers: list[Callable[[Exception], Any]] = []

    def on_quote(self, fn: Callable[[Quote], Any]) -> Callable[[Quote], Any]:
        """Decorator to register a quote handler."""
        self._quote_handlers.append(fn)
        return fn

    def on_snapshot(self, fn: Callable[[QuoteSnapshot], Any]) -> Callable[[QuoteSnapshot], Any]:
        """Decorator to register a snapshot handler."""
        self._snapshot_handlers.append(fn)
        return fn

    def on_error(self, fn: Callable[[Exception], Any]) -> Callable[[Exception], Any]:
        """Decorator to register an error handler."""
        self._error_handlers.append(fn)
        return fn

    def dispatch_quote(self, quote: Quote) -> None:
        """Dispatch a Quote to all registered handlers."""
        for handler in self._quote_handlers:
            try:
                handler(quote)
            except Exception as exc:
                logger.warning(f"Quote handler error in {handler.__name__}: {exc}")

    def dispatch_snapshot(self, snapshot: QuoteSnapshot) -> None:
        """Dispatch a QuoteSnapshot to all registered handlers."""
        for handler in self._snapshot_handlers:
            try:
                handler(snapshot)
            except Exception as exc:
                logger.warning(f"Snapshot handler error in {handler.__name__}: {exc}")

    def dispatch_error(self, exc: Exception) -> None:
        """Dispatch an error to all registered error handlers."""
        for handler in self._error_handlers:
            try:
                handler(exc)
            except Exception as e:
                logger.warning(f"Error handler error in {handler.__name__}: {e}")

    @property
    def has_handlers(self) -> bool:
        return bool(self._quote_handlers or self._snapshot_handlers)
