import logging
from sqlite3 import Connection
from typing import (
    Dict,
    List,
)

from message_handler_builder import Configs
from messagebus import (
    Event,
    Message,
    MessageBus,
)
from messagehandler import MessageHandlerBuilder
from messageprocessor import (
    DefaultMessageProcessorExecutorFactory,
    MessageProcessorMessageHandler,
)
from messageprocessorutil import LoggingProcessorCallback
from model.repository import (
    SqliteConnectionTransactionCallback,
    SqliteRepositoryFactory,
)
from nreports.builders import DataBuilderFactory
from nreports.interactor.build_report import BuildReportInteractor
from nreports.interactor.report_json_parser import ReportJsonParserInteractor
from nreports.processor import (
    BuildReportProcessor,
    ReportJsonParserProcessorBase,
)
from nreports.repository import (
    I18N,
    OrderAPIRepository,
    POSControllerRepository,
    StoreConfigRepository,
    UserRepository,
)
from nreports_api.shared.token import (
    TK_NREPORTS_BUILD_REPORT,
    TK_NREPORTS_REPORT_JSON_PARSER,
)

logger = logging.getLogger(name=__name__)


class NReportsMessageHandlerBuilder(MessageHandlerBuilder):

    def __init__(
        self,
        configs: Configs,
        message_bus: MessageBus,
    ) -> None:

        self.configs = configs
        self.message_bus = message_bus

        self.conn_mapping: Dict[MessageProcessorMessageHandler, List[Connection]] = {}
        self.sqlite_repository_factory = SqliteRepositoryFactory(database_dir=self.configs.database_dir)

        self.i18n_repository: I18N
        self.order_api_repository: OrderAPIRepository
        self.store_config_repository: StoreConfigRepository
        self.pos_controller_repository: POSControllerRepository

    def build_singletons(
        self,
    ) -> None:

        self._create_repositories()
        logger.info("Component started!")

    def build_message_handler(
        self,
        message: Message,
        event: Event,
    ) -> MessageProcessorMessageHandler:

        connections: List[Connection] = []

        data_builder_factory = DataBuilderFactory(
            message_bus=self.message_bus,
            order_api_repository=self.order_api_repository,
            store_config_repository=self.store_config_repository,
            i18n_repository=self.i18n_repository,
            extra_modules=self.configs.builder_extra_modules,
            images_path=self.configs.images_path,
            constants=self.configs.constants,
            user_repository=self.user_repository,
        )
        build_report_interactor = BuildReportInteractor(
            report_files=self.configs.report_files,
            data_builder_factory=data_builder_factory,
            i18n_repository=self.i18n_repository,
        )
        report_json_parser_interactor = ReportJsonParserInteractor(i18n_repository=self.i18n_repository)
        build_report_processor = BuildReportProcessor(interactor=build_report_interactor)
        report_json_parser_processor = ReportJsonParserProcessorBase(interactor=report_json_parser_interactor)

        message_handler = MessageProcessorMessageHandler(
            event_processors={},
            message_processors={
                TK_NREPORTS_BUILD_REPORT: build_report_processor,
                TK_NREPORTS_REPORT_JSON_PARSER: report_json_parser_processor,
            },
            executor_factory=DefaultMessageProcessorExecutorFactory(
                callbacks=[
                    LoggingProcessorCallback(logger=logger),
                    SqliteConnectionTransactionCallback(connections=connections),
                ]
            ),
        )

        self.conn_mapping[message_handler] = connections

        return message_handler

    def _create_repositories(
        self,
    ) -> None:

        self.order_api_repository = OrderAPIRepository(message_bus=self.message_bus)
        self.store_config_repository = StoreConfigRepository(message_bus=self.message_bus)
        self.pos_controller_repository = POSControllerRepository(message_bus=self.message_bus)
        self.user_repository = UserRepository(message_bus=self.message_bus)
        self.i18n_repository = I18N(
            message_bus=self.message_bus,
            pos_controller_repository=self.pos_controller_repository,
        )

    def destroy_message_handler(
        self,
        message_handler: MessageProcessorMessageHandler,
    ) -> None:

        if message_handler in self.conn_mapping:
            connections = self.conn_mapping[message_handler]
            for conn in connections:
                conn.close()
            del self.conn_mapping[message_handler]

    def destroy_singletons(
        self,
    ) -> None:

        logger.info("Component stopped!")
