# -*- coding: utf-8 -*-

from logging import Logger

import sysactions
from msgbus import MBEasyContext

from mbcontextmessagehandler import MbContextMessageBus
from messagebus import (
    Event,
    Message,
)
from messagehandler import (
    MessageHandler,
    MessageHandlerBuilder,
)
from messageprocessor import (
    DefaultMessageProcessorExecutorFactory,
    MessageProcessorMessageHandler,
)
from messageprocessorutil import LoggingProcessorCallback
from services.manager import DatabaseManager
from typing import Any

from services.interactor import (
    DiscountAppliedInteractor,
    GetConfiguredAlertsInteractor,
    OrderCanceledInteractor,
    POSAlertNotificationInteractor,
    BOHChangeNotificationConfigInteractor,
    BOHOrderPictureInteractor,
    UpdateAlertsInteractor,
)
from services.model import (
    Configs,
    ListenedEvents,
    ListenedTokens,
)
from externals.processor import (
    DiscountAppliedProcessor,
    GetConfiguredAlertsProcessor,
    OrderCanceledProcessor,
    POSAlertNotificationProcessor,
    BOHChangeNotificationConfigProcessor,
    BOHOrderPictureProcessor,
    UpdateAlertsProcessor,
)
from externals.repository import AlertsRepository
from externals.repository.api import AlertsAPIRepository
from services.services import (
    RetrySentEventService,
    UpdateService,
)


class AlertsMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(
        self,
        configs,            # type: Configs
        message_bus,        # type: MbContextMessageBus
        mb_context,         # type: MBEasyContext
        logger,             # type: Logger
        input_logger,       # type: Logger
        callback_logger,    # type: Logger
    ):
        # type: (...) -> None

        self.configs = configs
        self.message_bus = message_bus
        self.mb_context = mb_context
        self.logger = logger
        self.input_logger = input_logger
        self.callback_logger = callback_logger
        self.cache_manager = None
        sysactions.mbcontext = message_bus.mbcontext
        self.alerts_repository = None
        self.alerts_api_repository = None
        self.update_service = None
        self.database_manager = None

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

        self.alerts_repository = AlertsRepository(
            mb_context=self.mb_context,
            configs=self.configs,
            logger=self.logger,
        )
        self.alerts_api_repository = AlertsAPIRepository(
            configs=self.configs,
            logger=self.logger,
        )
        self.update_service = UpdateService(
            message_bus=self.message_bus,
            mb_context=self.mb_context,
            alerts_repository=self.alerts_repository,
            alerts_api_repository=self.alerts_api_repository,
            logger=self.logger,
        )
        retry_sent_event_service = RetrySentEventService(
            message_bus=self.message_bus,
            alerts_repository=self.alerts_repository,
            time_to_call=self.configs.alerts.time_calling,
            logger=self.logger,
        )
        retry_sent_event_service.start()

        self.database_manager = DatabaseManager(
            message_bus=self.message_bus,
            alerts_repository=self.alerts_repository,
            configs=self.configs,
            logger=self.logger,
        )
        self.database_manager.start()

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

        discount_applied_processor = DiscountAppliedProcessor(
            discount_applied_interactor=DiscountAppliedInteractor(
                alerts_repository=self.alerts_repository,
            )
        )
        get_configured_alerts_processor = GetConfiguredAlertsProcessor(
            get_configured_alerts_interactor=GetConfiguredAlertsInteractor(
                alerts_repository=self.alerts_repository
            )
        )
        order_canceled_processor = OrderCanceledProcessor(
            order_canceled_interactor=OrderCanceledInteractor(
                alerts_repository=self.alerts_repository,
            )
        )
        pos_alert_notification_processor = POSAlertNotificationProcessor(
            pos_alert_notification_interactor=POSAlertNotificationInteractor(
                alerts_repository=self.alerts_repository,
            )
        )
        boh_change_notification_config_processor = BOHChangeNotificationConfigProcessor(
            boh_change_notification_config_interactor=BOHChangeNotificationConfigInteractor(
                update_service=self.update_service,
                logger=self.logger,
            )
        )
        boh_order_picture_processor = BOHOrderPictureProcessor(
            boh_order_picture_interactor=BOHOrderPictureInteractor(
                message_bus=self.message_bus,
                logger=self.logger,
            )
        )
        update_alerts_processor = UpdateAlertsProcessor(
            update_alerts_interactor=UpdateAlertsInteractor(
                update_service=self.update_service,
            )
        )

        message_handler = MessageProcessorMessageHandler(
            event_processors={
                ListenedEvents.DISCOUNT_APPLIED: discount_applied_processor,
                ListenedEvents.ORDER_CANCELED: order_canceled_processor,
                ListenedEvents.POS_ALERT_NOTIFICATION_ACK: pos_alert_notification_processor,
                ListenedEvents.BOH_CHANGE_NOTIFICATION_CONFIG: boh_change_notification_config_processor,
                ListenedEvents.BOH_ORDER_PICTURE: boh_order_picture_processor,
            },
            message_processors={
                ListenedTokens.TK_ALERTS_GET_CONFIGURED_ALERTS.value: get_configured_alerts_processor,
                ListenedTokens.TK_ALERTS_UPDATE_ALERTS.value: update_alerts_processor,
            },
            executor_factory=DefaultMessageProcessorExecutorFactory(
                [
                    LoggingProcessorCallback(self.callback_logger)
                ]
            ),
        )

        return message_handler

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

        pass

    def destroy_message_handler(
        self,               # type: AlertsMessageHandlerBuilder
        message_handler,    # type: Any
    ):
        # type: (...) -> None

        self.database_manager.stop()
