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

from interactor.event import EventInteractor
from interactor.message.get_operators_logout_sessions import GetOperatorsLogoutSessionsInteractor
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 (
    GetOperatorsLogoutSessionsProcessor,
    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,
            ListenedEvents.DECLARED_AMOUNT: generic_event_processor,
            ListenedEvents.TRANSFER_CASH_OUT: generic_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)

        get_operators_logout_sessions_interactor = GetOperatorsLogoutSessionsInteractor(
            log_repository=self.log_model,
            event_dispatcher=self.event_dispatcher,
        )
        get_operators_logout_sessions_processor = GetOperatorsLogoutSessionsProcessor(
            interactor=get_operators_logout_sessions_interactor,
        )

        messages_processors = {
            BusTokens.TK_AUDITLOG_RESYNC: resync_message_processor,
            BusTokens.TK_AUDITLOG_GET_OPERATORS_LOGOUT_SESSIONS: get_operators_logout_sessions_processor,
        }

        return messages_processors
