#  Rubio - Rubika API library for python
#  Copyright (C) 2025-present Rubio <https://github.com/RubioTeam>
#  Github - https://github.com/RubioTeam/rubio.core


from __future__ import annotations

from collections import defaultdict
from typing import DefaultDict, List, Union
import rubio.core


class Dispatcher:
    def __init__(self, client: rubio.core.Client):
        self.client = client

        self.handlers: DefaultDict[
            rubio.core.enums.HandlerType,
            DefaultDict[int, List[rubio.core.Handler]]
        ] = defaultdict(lambda: defaultdict(list))

    def add_handler(
        self,
        type: rubio.core.enums.HandlerType,
        handler: rubio.core.Handler,
        group: int = 0
    ):
        """
        Add a handler for a specific event type.

        Parameters:
            type (rubio.core.enums.HandlerType):
                The type of event to handle (e.g., MESSAGE, EDITED, DELETED).

            handler (rubio.core.Handler):
                The handler object to register.

            group (int, default: 0):
                Priority group for the handler. Lower numbers execute first.

        Example:
            dp.add_handler(
                HandlerType.MESSAGE,
                MessageHandler(my_message_callback),
                group=0
            )
        """
        self.handlers[type][group].append(handler)

    def remove_handler(
        self,
        type: rubio.core.enums.HandlerType,
        handler: rubio.core.Handler,
        group: int = 0
    ):
        """
        Remove a previously registered handler.

        Parameters:
            type (rubio.core.enums.HandlerType):
                The event type the handler was registered for.

            handler (rubio.core.Handler):
                The handler object to remove.

            group (int, default: 0):
                The group the handler was registered in.

        Note:
            If the handler is not found in the specified group, no error is raised.
        """
        if type in self.handlers and group in self.handlers[type]:
            handlers = self.handlers[type][group]
            if handler in handlers:
                handlers.remove(handler)

    async def dispatch(
        self,
        update: Union[
            rubio.core.types.Update,
            rubio.core.types.InlineMessage
        ]
    ):
        """
        Dispatch an update to appropriate handlers.

        This method routes incoming updates to registered handlers based on
        the update type. Handlers are executed in group priority order.

        Parameters:
            update (Union[rubio.core.types.Update, rubio.core.types.InlineMessage]):
                The update object to process.

        Update Type Mapping:
            - "NewMessage" → HandlerType.MESSAGE
            - "UpdatedMessage" → HandlerType.EDITED
            - "RemovedMessage" → HandlerType.DELETED
            - "StartedBot" → HandlerType.START_BOT
            - "StoppedBot" → HandlerType.STOP_BOT
            - rubio.core.types.InlineMessage → HandlerType.INLINE

        Handler Execution Flow:
            1. Determine event type from update
            2. Get handlers for that event type
            3. Execute handlers in group order (lowest first)
            4. Within each group, execute handlers in registration order
            5. Stop processing group if rubio.core.StopPropagation is raised
            6. Continue to next handler if rubio.core.ContinuePropagation is raised

        Note:
            - Each handler's `check()` method is called first to verify if it should run
            - If `check()` returns True, the handler's `run()` method is executed
            - Handlers can raise StopPropagation to prevent further processing
            - Handlers can raise ContinuePropagation to skip to the next handler
        """

        if isinstance(update, rubio.core.types.InlineMessage):
            event_type = rubio.core.enums.HandlerType.INLINE
        else:
            if update.type == "NewMessage":
                event_type = rubio.core.enums.HandlerType.MESSAGE

            elif update.type == "UpdatedMessage":
                event_type = rubio.core.enums.HandlerType.EDITED

            elif update.type == "RemovedMessage":
                event_type = rubio.core.enums.HandlerType.DELETED

            elif update.type == "StartedBot":
                event_type = rubio.core.enums.HandlerType.START_BOT

            elif update.type == "StoppedBot":
                event_type = rubio.core.enums.HandlerType.STOP_BOT

        groups = self.handlers.get(event_type)
        if not groups:
            return

        for group in sorted(groups):
            for handler in groups[group]:
                try:
                    if await handler.check(self.client, update):
                        await handler.run(self.client, update)
                except rubio.core.StopPropagation:
                    break
                except rubio.core.ContinuePropagation:
                    continue