"""
Stripe Webhook Dispatcher

Type-safe webhook event dispatching with registered handlers.
Handlers are registered with decorators and receive typed event objects.
"""

from __future__ import annotations

import logging
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any, TypeVar

from lightwave.integrations.stripe.contracts import (
    StripeEvent,
    parse_event,
)

logger = logging.getLogger(__name__)

T = TypeVar("T", bound=StripeEvent)

# Type for handler functions
HandlerFunc = Callable[[StripeEvent], None]


@dataclass
class DispatchResult:
    """Result of dispatching a webhook event."""

    event_id: str
    event_type: str
    handled: bool
    handler_name: str | None = None
    error: str | None = None


@dataclass
class WebhookDispatcher:
    """
    Type-safe webhook event dispatcher.

    Maintains a registry of handlers for different event types and
    dispatches incoming events to the appropriate handler.

    Usage:
        dispatcher = WebhookDispatcher()

        @dispatcher.handler("checkout.session.completed")
        def handle_checkout(event: CheckoutSessionCompletedEvent) -> None:
            pass

        # Or use the module-level register_handler
        @register_handler("invoice.paid")
        def handle_invoice(event: InvoicePaidEvent) -> None:
            pass

        # Dispatch an event
        result = dispatcher.dispatch(raw_event_dict)
    """

    _handlers: dict[str, HandlerFunc] = field(default_factory=dict)
    _handler_names: dict[str, str] = field(default_factory=dict)

    def handler(self, event_type: str) -> Callable[[HandlerFunc], HandlerFunc]:
        """
        Decorator to register a handler for an event type.

        Args:
            event_type: Stripe event type (e.g., "checkout.session.completed")

        Returns:
            Decorator function
        """

        def decorator(fn: HandlerFunc) -> HandlerFunc:
            self._handlers[event_type] = fn
            self._handler_names[event_type] = fn.__name__
            logger.debug(f"Registered handler {fn.__name__} for {event_type}")
            return fn

        return decorator

    def register(self, event_type: str, handler: HandlerFunc) -> None:
        """
        Register a handler function for an event type.

        Args:
            event_type: Stripe event type
            handler: Handler function
        """
        self._handlers[event_type] = handler
        self._handler_names[event_type] = handler.__name__
        logger.debug(f"Registered handler {handler.__name__} for {event_type}")

    def get_handler(self, event_type: str) -> HandlerFunc | None:
        """
        Get the registered handler for an event type.

        Args:
            event_type: Stripe event type

        Returns:
            Handler function or None if not registered
        """
        return self._handlers.get(event_type)

    def get_registered_events(self) -> list[str]:
        """
        Get list of all registered event types.

        Returns:
            List of event type strings
        """
        return list(self._handlers.keys())

    def dispatch(self, raw_event: dict[str, Any]) -> DispatchResult:
        """
        Dispatch a raw webhook event to its handler.

        Parses the event into a typed Pydantic model and calls
        the registered handler if one exists.

        Args:
            raw_event: Raw event data from Stripe webhook

        Returns:
            DispatchResult with handling status
        """
        event_id = raw_event.get("id", "unknown")
        event_type = raw_event.get("type", "unknown")

        # Parse into typed event
        try:
            typed_event = parse_event(raw_event)
        except Exception as e:
            logger.error(f"Failed to parse event {event_id}: {e}")
            return DispatchResult(
                event_id=event_id,
                event_type=event_type,
                handled=False,
                error=f"Parse error: {e}",
            )

        # Find and call handler
        handler = self._handlers.get(event_type)
        if handler is None:
            logger.info(f"No handler for event type: {event_type}")
            return DispatchResult(
                event_id=event_id,
                event_type=event_type,
                handled=False,
            )

        try:
            handler(typed_event)
            logger.info(f"Handled {event_type} ({event_id}) with {self._handler_names[event_type]}")
            return DispatchResult(
                event_id=event_id,
                event_type=event_type,
                handled=True,
                handler_name=self._handler_names[event_type],
            )
        except Exception as e:
            logger.exception(f"Handler error for {event_type}: {e}")
            return DispatchResult(
                event_id=event_id,
                event_type=event_type,
                handled=False,
                handler_name=self._handler_names[event_type],
                error=str(e),
            )


# Global dispatcher instance
_global_dispatcher = WebhookDispatcher()


def register_handler(event_type: str) -> Callable[[HandlerFunc], HandlerFunc]:
    """
    Module-level decorator to register handlers with the global dispatcher.

    Usage:
        @register_handler("checkout.session.completed")
        def handle_checkout(event: CheckoutSessionCompletedEvent) -> None:
            pass
    """
    return _global_dispatcher.handler(event_type)


def dispatch_event(raw_event: dict[str, Any]) -> DispatchResult:
    """
    Dispatch an event using the global dispatcher.

    Args:
        raw_event: Raw event data from Stripe webhook

    Returns:
        DispatchResult with handling status
    """
    return _global_dispatcher.dispatch(raw_event)


def get_dispatcher() -> WebhookDispatcher:
    """
    Get the global webhook dispatcher.

    Returns:
        WebhookDispatcher instance
    """
    return _global_dispatcher
