from application.interactor import (
    BenefitRetryInteractor,
    BurnBenefitInteractor,
    GetBenefitInfoInteractor,
    ApplyBenefitInteractor,
    UnlockBenefitInteractor,
    OrderModifiedPaidInteractor,
    OrderModifiedVoidInteractor,
    OrderModifiedVoidLineInteractor,
    TestConnectionInteractor
)
from application.manager import BenefitRetryManager
from application.model import ListenedTokens, ListenedEvents, DefaultBenefitApplierRepository, BenefitAppliers
from application.model.configuration import Configurations
from application.processor import (
    GetBenefitInfoProcessor,
    ApplyBenefitProcessor,
    OrderModifiedPaidProcessor,
    OrderModifiedVoidProcessor,
    OrderModifiedVoidLineProcessor,
    NotMappedProcessor,
    TestConnectionProcessor
)
from application.repository.pos import DBRepository
from messagebus import Message, Event
from messagehandler import MessageHandlerBuilder
from messageprocessor import \
    MessageProcessorMessageHandler, \
    DefaultMessageProcessorExecutorFactory
from messageprocessorutil import LoggingProcessorCallback
from typing import Union, Dict


class ComponentMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(self, configs, db_repository, benefit_appliers_repositories):
        # type: (Configurations, DBRepository, Dict[BenefitAppliers: DefaultBenefitApplierRepository]) -> None

        self.logger = configs.logger
        self.configs = configs
        self.db_repository = db_repository
        self.benefit_appliers_repositories = benefit_appliers_repositories

        self.benefit_retry_manager = None  # type: Union[None, BenefitRetryManager]
        self.message_handler = None  # type: Union[None, MessageProcessorMessageHandler]

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

        default_params = [self.configs, self.db_repository, self.benefit_appliers_repositories]

        burn_benefit_interactor = BurnBenefitInteractor(*default_params)
        get_benefit_info_interactor = GetBenefitInfoInteractor(*default_params)
        apply_benefit_interactor = ApplyBenefitInteractor(*default_params)
        unlock_benefit_interactor = UnlockBenefitInteractor(*default_params)
        test_connection_interactor = TestConnectionInteractor(self.configs)

        order_modified_paid_interactor = OrderModifiedPaidInteractor(burn_benefit_interactor, *default_params)
        order_modified_void_interactor = OrderModifiedVoidInteractor(unlock_benefit_interactor, *default_params)
        order_modified_void_line_interactor = OrderModifiedVoidLineInteractor(unlock_benefit_interactor, *default_params)

        get_benefit_info_processor = GetBenefitInfoProcessor(get_benefit_info_interactor)
        apply_benefit_processor = ApplyBenefitProcessor(apply_benefit_interactor)

        order_modified_paid_processor = OrderModifiedPaidProcessor(order_modified_paid_interactor)
        order_modified_void_processor = OrderModifiedVoidProcessor(order_modified_void_interactor)
        order_modified_void_line_processor = OrderModifiedVoidLineProcessor(order_modified_void_line_interactor)
        not_mapped_processor = NotMappedProcessor()

        test_connection_processor = TestConnectionProcessor(test_connection_interactor)

        messages_processors = {
            ListenedTokens.TK_NCOUPON_APPLY_COUPON.value: apply_benefit_processor,
            ListenedTokens.TK_NCOUPON_GET_COUPON_INFO.value: get_benefit_info_processor,
            ListenedTokens.TK_NCOUPON_TEST_CONNECTION.value: test_connection_processor
        }

        events_processors = {
            ListenedEvents.ORDER_MODIFIED_PAID.value: order_modified_paid_processor,
            ListenedEvents.ORDER_MODIFIED_VOID.value: order_modified_void_processor,
            ListenedEvents.ORDER_MODIFIED_VOID_LINE.value: order_modified_void_line_processor,
            ListenedEvents.ORDER_MODIFIED.value: not_mapped_processor
        }

        callbacks = [LoggingProcessorCallback(self.logger)]

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

        self.benefit_retry_manager = self._build_benefits_retry_manager(
            burn_benefit_interactor=burn_benefit_interactor,
            unlock_benefit_interactor=unlock_benefit_interactor,
        )
        self.benefit_retry_manager.start()

    def build_message_handler(self, message, event):
        # type: (Message, Event) -> None

        return self.message_handler

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

        self.benefit_retry_manager.stop()

    def destroy_message_handler(self, message_handler):
        # type: (MessageHandlerBuilder) -> None

        return

    def _build_benefits_retry_manager(self, burn_benefit_interactor, unlock_benefit_interactor):
        # type: (BurnBenefitInteractor, UnlockBenefitInteractor) -> BenefitRetryManager

        interactor = BenefitRetryInteractor(
            self.configs,
            self.db_repository,
            burn_benefit_interactor,
            unlock_benefit_interactor
        )
        return BenefitRetryManager(self.configs, interactor)
