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

from messagebus import (
    Event,
    Message,
    MessageBus,
)
from messagehandler import (
    MessageHandler,
    MessageHandlerBuilder,
)
from messageprocessor import (
    DefaultMessageProcessorExecutorFactory,
    MessageProcessorMessageHandler,
)
from messageprocessorutil import LoggingProcessorCallback
from msgbus import MBEasyContext
from poshelper import PosModelRetriever
from typing import (
    Any,
    Optional,
    Dict,
)

from devicemanager.interactor.get_devices import GetDevicesInteractor
from devicemanager.interactor.get_used_service import GetUsedServiceInteractor
from devicemanager.interactor.update_devices_status import UpdateDevicesStatusInteractor
from devicemanager.model import (
    Configs,
)
from devicemanager.processor import (
    GetUsedServiceProcessor,
    GetDevicesProcessor,
    UpdateDevicesStatusProcessor,
)
from devicemanager.service import (
    UsedServiceCache,
    DeviceStatusService,
    GetDevicesService,
)
from externals.messagehandlerbuilder.token import ListenedTokens
from externals.persist import (
    ConnectionWrapper,
    PersistTransactionCallback,
)
from externals.sqlite_repository import SqliteDeviceManagerRepository


class DeviceManagerMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(
        self,
        configs,        # type: Configs
        message_bus,    # type: MessageBus
        mb_context,     # type: MBEasyContext
    ):
        # type: (...) -> None

        self.configs = configs
        self.message_bus = message_bus
        self.mb_context = mb_context

        self.used_service_cache = None  # type: Optional[UsedServiceCache]
        self.device_status_service = None  # type: Optional[DeviceStatusService]
        self.model_retriever = None  # type: Optional[PosModelRetriever]

        self.message_handler_conn_dict = {}  # type: Dict[MessageHandler, ConnectionWrapper]

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

        self.used_service_cache = UsedServiceCache(model_retriever=PosModelRetriever(self.mb_context))

        self.device_status_service = DeviceStatusService(
            device_configs=self.configs.device_configs,
        )
        conn = ConnectionWrapper(
            mb_context=self.mb_context,
            service_name=self.configs.persistence_name,
        )
        repository = SqliteDeviceManagerRepository(conn=conn)
        self.device_status_service.initialize_cache(repository=repository)
        conn.close()

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

        conn = ConnectionWrapper(
            mb_context=self.mb_context,
            service_name=self.configs.persistence_name,
        )

        repository = SqliteDeviceManagerRepository(conn=conn)

        get_devices_service = GetDevicesService(
            repository=repository,
            device_configs=self.configs.device_configs,
        )

        get_used_service_interactor = GetUsedServiceInteractor(
            device_status_service=self.device_status_service,
            used_service_cache=self.used_service_cache,
            sector_config=self.configs.sector_config,
            brand_config=self.configs.brand_config,
        )

        get_devices_interactor = GetDevicesInteractor(
            get_devices_service=get_devices_service,
        )

        update_devices_interactor = UpdateDevicesStatusInteractor(
            repository=repository,
            get_devices_service=get_devices_service,
            device_status_service=self.device_status_service,
            message_bus=self.message_bus,
        )

        get_devices_processor = GetDevicesProcessor(get_devices_interactor=get_devices_interactor)

        get_used_service_processor = GetUsedServiceProcessor(get_used_service_interactor=get_used_service_interactor)

        update_devices_processor = UpdateDevicesStatusProcessor(
            update_devices_interactor=update_devices_interactor,
        )

        message_handler = MessageProcessorMessageHandler(
            event_processors=None,
            message_processors={
                ListenedTokens.TK_GET_USED_SERVICE.value: get_used_service_processor,
                ListenedTokens.TK_GET_DEVICES.value: get_devices_processor,
                ListenedTokens.TK_UPDATE_DEVICE_STATUS.value: update_devices_processor,
            },
            executor_factory=DefaultMessageProcessorExecutorFactory(
                callbacks=
                [
                    PersistTransactionCallback(
                        conn=conn,
                        do_not_need_transaction_processors=[
                            get_devices_processor,
                            get_used_service_processor,
                        ]
                    ),
                    LoggingProcessorCallback(
                        logger=logging.getLogger("devicemanager.LoggingProcessorCallback")
                    ),
                ]
            ),
        )

        self.message_handler_conn_dict[message_handler] = conn

        return message_handler

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

        pass

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

        if message_handler in self.message_handler_conn_dict:
            self.message_handler_conn_dict[message_handler].close()
            del self.message_handler_conn_dict[message_handler]
