from typing import Dict, List, Optional, Type

from edpdependencyinjection import DependencyContext
from messageprocessor import MessageProcessorMessageHandler, MessageProcessorCallback

from ._AutoMappedEventProcessorBuilder import AutoMappedEventProcessorBuilder
from ._AutoMappedMessageProcessorBuilder import AutoMappedMessageProcessorBuilder
from ._DiEventMessageProcessorBuilder import DiEventMessageProcessorBuilder
from ._DiMessageMessageProcessorBuilder import DiMessageMessageProcessorBuilder
from ._DiMessageProcessorExecutorFactory import DiMessageProcessorExecutorFactory
from ._EventProcessorDefinition import EventProcessorDefinition
from ._MessageProcessorDefinition import MessageProcessorDefinition
from ._utils import AcceptableProcessorDefinition


class DiMessageProcessorMessageHandler(MessageProcessorMessageHandler):
    def __init__(
        self,
        dependency_context: DependencyContext,
        event_processor_definitions: Optional[Dict[str, AcceptableProcessorDefinition]] = None,
        message_processor_definitions: Optional[Dict[int, AcceptableProcessorDefinition]] = None,
        callback_definitions: Optional[List[Type[MessageProcessorCallback]]] = None,
        subject_counter: Optional[Dict[str, int]] = None
    ):
        self.dependency_context = dependency_context

        all_event_definitions: Dict[str, AcceptableProcessorDefinition] = {}
        all_message_definitions: Dict[int, AcceptableProcessorDefinition] = {}

        if event_processor_definitions is not None:
            all_event_definitions.update(event_processor_definitions)

        if message_processor_definitions is not None:
            all_message_definitions.update(message_processor_definitions)

        self._discover_event_builders(all_event_definitions)
        self._discover_message_builders(all_message_definitions)

        event_processors = None
        if all_event_definitions:
            event_builder = DiEventMessageProcessorBuilder(dependency_context, all_event_definitions)
            event_processors = event_builder.build_message_processor_dict()

        message_processors = None
        if all_message_definitions:
            message_builder = DiMessageMessageProcessorBuilder(dependency_context, all_message_definitions)
            message_processors = message_builder.build_message_processor_dict()

        executor_factory = None
        if callback_definitions is not None:
            executor_factory = DiMessageProcessorExecutorFactory(dependency_context, callback_definitions)

        super().__init__(event_processors, message_processors, executor_factory, subject_counter)

    def _discover_event_builders(self, definitions: Dict[str, AcceptableProcessorDefinition]):
        builder_types = self.dependency_context.get_dependencies_by_parent(AutoMappedEventProcessorBuilder)
        for builder_type in builder_types:
            builder_instance = self.dependency_context.get_instance(builder_type)
            for key, value in builder_instance.build_events().items():
                if isinstance(value, EventProcessorDefinition):
                    definitions[key] = value.processor_type
                else:
                    definitions[key] = value

    def _discover_message_builders(self, definitions: Dict[int, AcceptableProcessorDefinition]):
        builder_types = self.dependency_context.get_dependencies_by_parent(AutoMappedMessageProcessorBuilder)
        for builder_type in builder_types:
            builder_instance = self.dependency_context.get_instance(builder_type)
            for token, value in builder_instance.build_messages().items():
                if isinstance(value, MessageProcessorDefinition):
                    definitions[token] = value.processor_type
                else:
                    definitions[token] = value