import logging
from typing import (
    Dict,
    Optional,
    Union,
)

from messagebus import (
    LowLevelMessageBus,
    Message,
    NakMessage,
)
from messagehandler import MessageHandler
from ._DefaultMessageProcessorExecutorFactory import DefaultMessageProcessorExecutorFactory
from ._MessageMessageProcessorBuilder import MessageMessageProcessorBuilder
from ._MessageProcessor import MessageProcessor
from ._MessageProcessorExecutorFactory import MessageProcessorExecutorFactory

logger = logging.getLogger("MessageProcessor.MessageProcessorMessageHandler")


class MessageProcessorMessageHandler(MessageHandler):
    def __init__(
        self,
        message_processors,     # type: Dict[int, Union[MessageProcessor, MessageMessageProcessorBuilder]]
        executor_factory=None,  # type: Optional[MessageProcessorExecutorFactory]
    ):
        # type: (...) -> None
        self.message_processors = message_processors
        self.executor_factory = executor_factory
        if self.executor_factory is None:
            self.executor_factory = DefaultMessageProcessorExecutorFactory([])

    def handle_message(self, message_bus, message):
        # type: (LowLevelMessageBus, Message) -> None

        if message.token not in self.message_processors:
            message_bus.reply_message(message, NakMessage())
            return

        message_processor = self._get_message_processor(message)

        executor = self.executor_factory.build_executor(message_processor)
        executor.execute_processor(message_bus, message)

    def _get_message_processor(self, message):
        # type: (Message) -> MessageProcessor

        builder = self.message_processors[message.token]
        if isinstance(builder, MessageMessageProcessorBuilder):
            message_processor = builder.build_message_processor(message.token)
        else:
            message_processor = builder
        return message_processor
