# -*- coding: utf-8 -*-
from logging import Logger

from interactor.event import EventInteractor
from interactor.resync import ResyncInteractor

from mbcontextmessagehandler import MbContextMessageBus
from messagehandler import MessageHandlerBuilder
from messageprocessor import MessageProcessor, DefaultMessageProcessorExecutorFactory, MessageProcessorMessageHandler
from messageprocessorutil import LoggingProcessorCallback
from model.config import Config
from model.event import ListenedEvents
from model.tokens import BusTokens
from processor.event import (
    OrderEventProcessor,
    PosEventProcessor,
    TableEventProcessor,
    ProductionEventProcessor,
    GenericEventProcessor
)
from processor.message import ResyncMessageProcessor
from repository import LogRepository
from services import EventDispatcher
from typing import Dict, Optional


class ServiceMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(self, logger, config, message_bus):
        # type: (Logger, Config, MbContextMessageBus) -> None

        self.logger = logger
        self.config = config
        self.message_bus = message_bus

        self.callbacks = None
        self.message_handler = None
        self.log_model = None
        self.event_dispatcher = None

    def build_singletons(self):
        # type: () -> None

        self.callbacks = [LoggingProcessorCallback(self.logger)]
        self.log_model = LogRepository(self.config.output_folder, self.config.encode, self.logger, self.config)
        self.event_dispatcher = EventDispatcher(self.message_bus)

        events_processors = self._build_events_processors()
        messages_processors = self._build_messages_processors()
        default_message_processor_executor_factory = DefaultMessageProcessorExecutorFactory(self.callbacks)

        self.message_handler = MessageProcessorMessageHandler(
            event_processors=events_processors,
            message_processors=messages_processors,
            executor_factory=default_message_processor_executor_factory
        )

    def build_message_handler(self, message=None, event=None):
        return self.message_handler

    def destroy_message_handler(self, message_handler):
        # nothing to destroy
        pass

    def destroy_singletons(self):
        # nothing to destroy
        pass

    def _build_events_processors(self):
        # type: () -> Optional[Dict[str, MessageProcessor]]

        event_interactor = EventInteractor(self.log_model, self.event_dispatcher)

        order_event_processor = OrderEventProcessor(event_interactor)
        table_event_processor = TableEventProcessor(event_interactor)
        pos_event_processor = PosEventProcessor(event_interactor)
        production_event_processor = ProductionEventProcessor(event_interactor)
        generic_event_processor = GenericEventProcessor(event_interactor)

        events_processors = {
            ListenedEvents.HVAUDIT: pos_event_processor,
            ListenedEvents.ORDER_MODIFIED: order_event_processor,
            ListenedEvents.ORDER_STATE: order_event_processor,
            ListenedEvents.TABLE_CLOSED: table_event_processor,
            ListenedEvents.PRODUCTION_ORDER_EVENT: production_event_processor,
            ListenedEvents.ORDER_REPROCESS: order_event_processor,
            ListenedEvents.POS_STATECHANGED: pos_event_processor,
            ListenedEvents.POS_UPDATER_LOGGER: generic_event_processor,
            ListenedEvents.STORE_STATUS: generic_event_processor,
            ListenedEvents.GLOBAL_RESTART: generic_event_processor,
        }

        if not self.config.order_modified_by_message:
            events_processors[ListenedEvents.ORDER_MODIFIED] = order_event_processor

        return events_processors

    def _build_messages_processors(self):
        # type: () -> Optional[Dict[str, MessageProcessor]]

        resync_interactor = ResyncInteractor(self.log_model, self.event_dispatcher)
        resync_message_processor = ResyncMessageProcessor(resync_interactor)

        event_interactor = EventInteractor(self.log_model, self.event_dispatcher)
        order_message_processor = OrderEventProcessor(event_interactor, True, not self.config.order_modified_by_message)

        messages_processors = {
            BusTokens.TK_AUDITLOG_RESYNC: resync_message_processor,
            BusTokens.TK_SALE_ORDER_MODIFIED: order_message_processor
        }

        return messages_processors
