import logging
from typing import Optional

from messagehandler import MessageHandlerBuilder
from messageprocessor import (
    DefaultMessageProcessorExecutorFactory,
    MessageProcessorMessageHandler,
)
from messageprocessorutil import LoggingProcessorCallback
from service_locator_api.shared.token import (
    TK_SERVICE_LOCATOR_KEEP_ALIVE,
    TK_SERVICE_LOCATOR_LOOKUP_SERVICE,
    TK_SERVICE_LOCATOR_REGISTER_SERVICE,
)
from zeromqservicelocator import (
    InMemoryRegistrationRepository,
    RedisRegistrationRepository,
    ServiceLocator,
)
from zeromqservicelocator.processor import (
    KeepAliveProcessor,
    LocateServiceProcessor,
    RegisterServiceProcessor,
)
from .config import (
    Configuration,
    StoreStrategy,
)


class ServiceLocatorMessageHandlerBuilder(MessageHandlerBuilder):
    def __init__(
        self,
        config: Configuration,
    ) -> None:
        self.config = config

        self.service_locator: Optional[ServiceLocator] = None
        self.registration_repository: Optional[RedisRegistrationRepository] = None

    def build_singletons(self):
        if self.config.store_strategy == StoreStrategy.IN_MEMORY:
            self.registration_repository = InMemoryRegistrationRepository()
        else:
            self.registration_repository = RedisRegistrationRepository(
                host=self.config.redis_config.host,
                port=self.config.redis_config.port,
                db=self.config.redis_config.db,
                expiration=self.config.registration_expiration,
            )
        self.service_locator = ServiceLocator(
            registration_repository=self.registration_repository,
            registration_expiration=self.config.registration_expiration,
        )

    def build_message_handler(self, message):
        handled_tokens = {
            TK_SERVICE_LOCATOR_REGISTER_SERVICE: RegisterServiceProcessor(self.service_locator),
            TK_SERVICE_LOCATOR_LOOKUP_SERVICE: LocateServiceProcessor(self.service_locator),
            TK_SERVICE_LOCATOR_KEEP_ALIVE: KeepAliveProcessor(self.service_locator),
        }
        return MessageProcessorMessageHandler(
            message_processors=handled_tokens,
            executor_factory=DefaultMessageProcessorExecutorFactory(
                [
                    LoggingProcessorCallback(logging.getLogger("servicelocator.LoggingProcessorCallback"))
                ]
            )
        )

    def destroy_message_handler(self, message_handler):
        pass

    def destroy_singletons(self):
        self.service_locator.dispose()
        if self.config.store_strategy == StoreStrategy.REDIS:
            self.registration_repository.close()
