import logging
import threading
from abc import (
    ABC,
    abstractmethod,
)
from typing import (
    Generic,
    Optional,
    TypeVar,
)

from contextmessagebus import MultiContextMessageBus
from messagebus import (
    Event,
    Message,
    MessageBus,
)
from messagehandler import (
    MessageHandler,
    MessageHandlerBuilder,
)

from edpconfigprovider.util import ConfigMapper

T = TypeVar("T")


logger = logging.getLogger(__name__)


class ConfigProviderMessageHandlerBuilder(Generic[T], MessageHandlerBuilder, ABC):
    def __init__(
        self,
        config_transformer: ConfigMapper[T],
        message_bus: Optional[MessageBus] = None
    ):
        self.config_transformer = config_transformer
        self.message_bus = message_bus

    def build_message_handler(
        self,
        message: Optional[Message],
        event: Optional[Event],
    ) -> MessageHandler:
        try:
            context_name = self._get_context_name(message, event)
        except KeyError:
            logger.error("The 'context' was not present in the message or event: message: %s event: %s", message, event)
            raise RuntimeError("No context")

        setattr(threading.current_thread(), '_edp_context_name', context_name)
        if isinstance(self.message_bus, MultiContextMessageBus):
            self.message_bus.set_current_context(context_name)

        return self.build_message_handler_with_config(config=self.config_transformer.build_config())


    @abstractmethod
    def build_message_handler_with_config(self, config: T) -> MessageHandler:
        raise NotImplementedError()

    @staticmethod
    def _get_context_name(message, event):
        if message is not None:
            return message.headers["context"]
        else:
            return event.headers["context"]
