# core/handler.py
from __future__ import annotations

from typing import Awaitable, Callable

import structlog

from core.auth import AuthManager
from core.chat import ChatManager
from core.protocol import (
    IncomingCallback,
    IncomingCommand,
    IncomingEvent,
    IncomingMessage,
    OutgoingEvent,
)
from core.settings import SettingsManager
from sdk.interface import PlatformClient

logger = structlog.get_logger(__name__)

HandlerFn = Callable[..., Awaitable[list[OutgoingEvent]]]


class EventDispatcher:
    def __init__(
        self,
        platform: PlatformClient,
        chat_mgr: ChatManager,
        auth_mgr: AuthManager,
        settings_mgr: SettingsManager,
    ) -> None:
        self._platform = platform
        self._chat_mgr = chat_mgr
        self._auth_mgr = auth_mgr
        self._settings_mgr = settings_mgr
        self._handlers: dict[type, dict[str, HandlerFn]] = {
            IncomingCommand: {},
            IncomingMessage: {},
            IncomingCallback: {},
        }

    def register(self, event_type: type, key: str, handler: HandlerFn) -> None:
        self._handlers[event_type][key] = handler

    async def dispatch(self, event: IncomingEvent) -> list[OutgoingEvent]:
        event_type = type(event)
        handlers = self._handlers.get(event_type, {})
        key = self._routing_key(event)
        handler = handlers.get(key) or handlers.get("*")

        if handler is None:
            logger.warning("No handler registered", event_type=event_type.__name__, key=key)
            return []

        return await handler(
            event=event,
            chat_mgr=self._chat_mgr,
            auth_mgr=self._auth_mgr,
            settings_mgr=self._settings_mgr,
            platform=self._platform,
        )

    def _routing_key(self, event: IncomingEvent) -> str:
        if isinstance(event, IncomingCommand):
            return event.command
        if isinstance(event, IncomingCallback):
            return event.action
        if isinstance(event, IncomingMessage) and event.attachments:
            return event.attachments[0].type
        return "*"
