"""How the handler routes incoming messages (by token) to the right processor.

Unlike events, an unmapped message is not an error: the contract is that the
handler replies NAK on the bus so the sender is not left waiting.
"""
from messagebus import DefaultToken, Message, NakMessage

from messageprocessor import MessageMessageProcessorBuilder

from testutil import MarkerProcessor

ORDERS_TOKEN = 0x1A2B
UNKNOWN_TOKEN = 0x9999


def test_routes_message_to_processor_mapped_by_token(build_handler, message_bus):
    handler = build_handler(message_processors={ORDERS_TOKEN: MarkerProcessor("orders-processor")})

    handler.handle_message(message_bus, Message(token=ORDERS_TOKEN, data=b""))

    assert [e.subject for e in message_bus.published_events] == ["orders-processor"]


def test_passes_message_data_through_to_the_processor(build_handler, message_bus):
    handler = build_handler(message_processors={ORDERS_TOKEN: MarkerProcessor("orders-processor")})

    handler.handle_message(message_bus, Message(token=ORDERS_TOKEN, data=b"the-payload"))

    assert message_bus.published_events[0].data == b"the-payload"


def test_replies_nak_when_token_is_unknown(build_handler, message_bus):
    handler = build_handler(message_processors={ORDERS_TOKEN: MarkerProcessor("orders-processor")})
    message = Message(token=UNKNOWN_TOKEN, data=b"")

    handler.handle_message(message_bus, message)

    assert len(message_bus.message_replies) == 1
    replied_to, reply = message_bus.message_replies[0]
    assert replied_to is message
    assert isinstance(reply, NakMessage)
    assert reply.token == DefaultToken.TK_SYS_NAK
    assert message_bus.published_events == []


def test_replies_nak_when_no_message_processors_configured(build_handler, message_bus):
    handler = build_handler(message_processors=None)

    handler.handle_message(message_bus, Message(token=ORDERS_TOKEN, data=b""))

    assert len(message_bus.message_replies) == 1
    _, reply = message_bus.message_replies[0]
    assert isinstance(reply, NakMessage)


def test_builds_message_processor_lazily_from_a_builder(build_handler, message_bus):
    class RecordingBuilder(MessageMessageProcessorBuilder):
        def __init__(self):
            self.received_token = None

        def build_message_processor(self, token):
            self.received_token = token
            return MarkerProcessor("lazily-built")

    builder = RecordingBuilder()
    handler = build_handler(message_processors={ORDERS_TOKEN: builder})

    handler.handle_message(message_bus, Message(token=ORDERS_TOKEN, data=b""))

    assert builder.received_token == ORDERS_TOKEN
    assert [e.subject for e in message_bus.published_events] == ["lazily-built"]
