from application.interactor import (
    GetLoyaltyCustomerInfoInteractor,
    LockBenefitInteractor,
    LoyaltyAvailableInteractor,
    LoyaltyIdentifierInteractor,
    GetAndLockCouponInteractor,
)
from application.interactor.burn_voucher import BurnVoucherInteractor
from application.interactor.unlock_voucher import UnlockVoucherInteractor
from application.model.configuration import Configurations
from application.model.customexception import (
    ClientCustomError,
    NotFoundError,
    InUseError,
    GoneError,
)
from application.processor import (
    GetLoyaltyCustomerInfoProcessor,
    BurnVoucherProcessor,
    UnlockVoucherProcessor,
    LoyaltyAvailableProcessor,
    LoyaltyIdentifierProcessor,
)
from application.processor.lock_benefit import LockBenefitProcessor
from application.processor.tokens import ListenedToken
from application.processor.get_and_lock_coupon import GetAndLockCouponProcessor
from application.repository.api import APIRepository
from mbcontextmessagehandler import MbContextMessageBus
from messagebus import Message, Event
from messagehandler import MessageHandlerBuilder
from messageprocessor import (
    MessageProcessorMessageHandler,
    DefaultMessageProcessorExecutorFactory,
)
from messageprocessorutil import LoggingProcessorCallback
from typing import Union


class ComponentMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(
        self,
        configs,        # type: Configurations
        message_bus,    # type: MbContextMessageBus
    ):
        # type: (...) -> None

        self.logger = configs.logger
        self.configs = configs
        self.api_repository = APIRepository(
            configs=self.configs,
            message_bus=message_bus,
        )

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

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

        get_loyalty_customer_info_interactor = GetLoyaltyCustomerInfoInteractor(
            api_repository=self.api_repository,
        )
        get_and_lock_coupon_interactor = GetAndLockCouponInteractor(api_repository=self.api_repository)
        lock_benefit_interactor = LockBenefitInteractor(api_repository=self.api_repository)
        burn_voucher_interactor = BurnVoucherInteractor(api_repository=self.api_repository)
        unlock_voucher_interactor = UnlockVoucherInteractor(api_repository=self.api_repository)
        loyalty_available_interactor = LoyaltyAvailableInteractor(self.configs)
        loyalty_identifier_interactor = LoyaltyIdentifierInteractor(configs=self.configs)

        get_loyalty_customer_info_processor = GetLoyaltyCustomerInfoProcessor(
            interactor=get_loyalty_customer_info_interactor,
        )
        get_and_lock_voucher_processor = GetAndLockCouponProcessor(interactor=get_and_lock_coupon_interactor)
        lock_benefit_processor = LockBenefitProcessor(interactor=lock_benefit_interactor)
        burn_voucher_processor = BurnVoucherProcessor(interactor=burn_voucher_interactor)
        unlock_voucher_processor = UnlockVoucherProcessor(interactor=unlock_voucher_interactor)
        loyalty_available_processor = LoyaltyAvailableProcessor(loyalty_available_interactor)
        loyalty_identifier_processor = LoyaltyIdentifierProcessor(interactor=loyalty_identifier_interactor)

        messages_processors = {
            ListenedToken.TK_LOYALTY_GET_LOYALTY_ID.value: get_loyalty_customer_info_processor,
            ListenedToken.TK_LOYALTY_GET_AND_LOCK_VOUCHER.value: get_and_lock_voucher_processor,
            ListenedToken.TK_LOYALTY_LOCK_BENEFIT.value: lock_benefit_processor,
            ListenedToken.TK_LOYALTY_BURN_VOUCHER.value: burn_voucher_processor,
            ListenedToken.TK_LOYALTY_UNLOCK_VOUCHER.value: unlock_voucher_processor,
            ListenedToken.TK_LOYALTY_IS_AVAILABLE.value: loyalty_available_processor,
            ListenedToken.TK_LOYALTY_GET_ID_TYPE.value: loyalty_identifier_processor,
        }

        callbacks = [
            LoggingProcessorCallback(
                logger=self.logger,
                ignored_exceptions=[
                    ClientCustomError,
                    NotFoundError,
                    InUseError,
                    GoneError,
                ]
            )
        ]

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

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

        return self.message_handler

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

        return

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

        return
