"""Event system for decoupled communication between components."""

from __future__ import annotations

import asyncio
from collections import defaultdict
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Awaitable, Callable

# Type alias for event handlers
EventHandler = Callable[["Event"], Awaitable[None] | None]


class EventType(Enum):
    """Types of events in the system."""

    # Task events
    TASK_LIST_UPDATED = "task_list_updated"

    # Status events
    STATUS_MESSAGE = "status_message"

    # Tool events
    TOOL_STARTED = "tool_started"


@dataclass
class Event:
    """Base event class."""

    event_type: EventType
    data: dict[str, Any] = field(default_factory=dict)
    timestamp: float = field(default_factory=lambda: __import__("time").time())


@dataclass
class TaskEvent(Event):
    """Event for task/todo updates."""

    def __init__(
        self,
        event_type: EventType,
        todos: list[dict[str, str]],
    ):
        super().__init__(
            event_type=event_type,
            data={"todos": todos},
        )


@dataclass
class StatusEvent(Event):
    """Event for status display updates."""

    def __init__(
        self,
        message: str,
        progress: tuple[int, int] | None = None,
    ):
        super().__init__(
            event_type=EventType.STATUS_MESSAGE,
            data={
                "message": message,
                "progress": progress,
            },
        )


@dataclass
class ToolEvent(Event):
    """Event for tool usage notifications."""

    def __init__(
        self,
        event_type: EventType,
        tool_name: str,
        tool_input: dict[str, Any] | None = None,
    ):
        super().__init__(
            event_type=event_type,
            data={
                "tool_name": tool_name,
                "tool_input": tool_input or {},
            },
        )


class EventBus:
    """Simple async-aware event bus for component communication.

    Design principles:
    - Lightweight (no external dependencies)
    - Supports both sync and async handlers
    - Type-safe event routing via EventType enum
    """

    def __init__(self):
        self._handlers: dict[EventType, list[EventHandler]] = defaultdict(list)

    def subscribe(self, event_type: EventType, handler: EventHandler) -> None:
        """Register a handler for an event type.

        Args:
            event_type: Type of event to listen for
            handler: Sync or async function to handle the event
        """
        self._handlers[event_type].append(handler)

    def unsubscribe(self, event_type: EventType, handler: EventHandler) -> None:
        """Remove a handler registration."""
        if handler in self._handlers[event_type]:
            self._handlers[event_type].remove(handler)

    async def publish(self, event: Event) -> None:
        """Publish an event to all subscribed handlers.

        All handlers are called concurrently for responsiveness.
        """
        handlers = self._handlers.get(event.event_type, [])
        if not handlers:
            return

        # Run all handlers concurrently
        tasks = []
        for handler in handlers:
            try:
                result = handler(event)
                if asyncio.iscoroutine(result):
                    tasks.append(result)
            except Exception as e:
                # Log but don't fail the publish
                import sys

                print(f"Event handler error: {e}", file=sys.stderr)

        if tasks:
            await asyncio.gather(*tasks, return_exceptions=True)

    def publish_sync(self, event: Event) -> None:
        """Synchronously publish (creates task if in async context)."""
        try:
            loop = asyncio.get_running_loop()
            loop.create_task(self.publish(event))
        except RuntimeError:
            # No running loop, ignore
            pass
