from messagebus import AckMessage, NakMessage, MessageBus, Message, Event, BadRequestMessage
from messageprocessorutil import UuidMessageProcessor
from zeromqeventmanager.model.dto import SubscribeRequest, SubscribeResponse

from .._EventManager import EventManager
from event_manager_api.shared.error import subscribe_errors


class SubscribeProcessor(UuidMessageProcessor):

    def __init__(self, event_manager, event_name=None):
        # type: (EventManager, str) -> None
        super(SubscribeProcessor, self).__init__(event_name)
        self.event_manager = event_manager

    def parse_data(self, data):
        parts = data.split(b"\0")
        if len(parts) < 3:
            raise SubscribeProcessor.InvalidRequest(error_code=subscribe_errors.INVALID_DATA)

        sub_id = parts[0]
        if sub_id == b"":
            sub_id = None
        else:
            sub_id = sub_id.decode("utf-8")
        service_name = parts[1].decode("utf-8")
        if service_name.strip() == "":
            raise SubscribeProcessor.InvalidRequest(error_code=subscribe_errors.EMPTY_SERVICE_NAME)

        subjects = list(map(lambda x: x.decode("utf-8"), parts[2:]))
        for subject in subjects:
            if subject.strip() == "":
                raise SubscribeProcessor.InvalidRequest(error_code=subscribe_errors.EMPTY_SUBJECT)

        return SubscribeRequest(sub_id, service_name, subjects)

    def call_business(self, request):
        # type: (SubscribeRequest) -> SubscribeResponse
        return self.event_manager.subscribe(request.sub_id, request.service_name, request.subjects)

    def format_response(self, message_bus, message, event, input_obj, response):
        # type: (MessageBus, Message, Event, SubscribeRequest, SubscribeResponse) -> None
        data = b"\0".join([response.sub_id.encode("utf-8"),
                           response.pub_address.encode("utf-8"),
                           response.pull_address.encode("utf-8")])
        message_bus.reply_message(message, AckMessage(data=data))

    def format_exception(self, message_bus, message, event, input_obj, exception):
        message_bus.reply_message(message, NakMessage(data=str(exception).encode("utf-8")))

    def format_parse_exception(self, message_bus, message, event, data, exception):
        if isinstance(exception, SubscribeProcessor.InvalidRequest):
            reply = BadRequestMessage(
                error_code=exception.error_code,
                error_message=subscribe_errors.error_message_map[exception.error_code],
            )
        else:
            reply = NakMessage(data=str(exception).encode("utf-8"))
        message_bus.reply_message(
            message=message,
            reply_message=reply,
        )

    class InvalidRequest(Exception):
        def __init__(self, error_code: int):
            self.error_code = error_code
