"""Behaviour the UuidMessageProcessor base class gives a concrete processor:
a request id that defaults to a fresh UUID per run but can be supplied by the
request context (e.g. a Lambda's aws_request_id), and a processor name that
defaults to the class name but can be overridden.

Observed through the request id / processor name a callback receives.
"""
import uuid

import pytest
from messagebus import Event

from messageprocessorutil import UuidMessageProcessor, set_request_id, clear


@pytest.fixture(autouse=True)
def clear_request_context():
    """Keep the thread-local request id from leaking between tests."""
    clear()
    yield
    clear()


class OrderUuidProcessor(UuidMessageProcessor):
    def parse_data(self, data=None):
        return data

    def call_business(self, obj):
        return obj

    def format_response(self, message_bus, message, event, input_obj, result):
        pass

    def format_exception(self, message_bus, message, event, input_obj, exception):
        pass

    def format_parse_exception(self, message_bus, message, event, data, exception):
        pass


def test_generates_a_unique_request_id_for_each_run(build_handler, message_bus, recording_callback):
    handler = build_handler(
        event_processors={"orders": OrderUuidProcessor()},
        callbacks=[recording_callback],
    )

    handler.handle_event(message_bus, Event("orders", None, b""))
    handler.handle_event(message_bus, Event("orders", None, b""))

    first_id, second_id = recording_callback.request_ids
    assert first_id != second_id
    uuid.UUID(first_id)   # parses as a valid UUID
    uuid.UUID(second_id)


def test_uses_the_request_id_from_the_context_when_one_is_set(build_handler, message_bus, recording_callback):
    handler = build_handler(
        event_processors={"orders": OrderUuidProcessor()},
        callbacks=[recording_callback],
    )

    set_request_id("aws-request-id-123")
    handler.handle_event(message_bus, Event("orders", None, b""))

    assert recording_callback.request_ids[0] == "aws-request-id-123"


def test_falls_back_to_a_fresh_uuid_once_the_context_is_cleared(build_handler, message_bus, recording_callback):
    handler = build_handler(
        event_processors={"orders": OrderUuidProcessor()},
        callbacks=[recording_callback],
    )

    set_request_id("aws-request-id-123")
    handler.handle_event(message_bus, Event("orders", None, b""))
    clear()
    handler.handle_event(message_bus, Event("orders", None, b""))

    from_context, fallback = recording_callback.request_ids
    assert from_context == "aws-request-id-123"
    assert fallback != "aws-request-id-123"
    uuid.UUID(fallback)  # parses as a valid UUID


def test_uses_the_class_name_as_the_processor_name_by_default(build_handler, message_bus, recording_callback):
    handler = build_handler(
        event_processors={"orders": OrderUuidProcessor()},
        callbacks=[recording_callback],
    )

    handler.handle_event(message_bus, Event("orders", None, b""))

    assert recording_callback.event_names[0] == "OrderUuidProcessor"


def test_uses_a_provided_event_name_when_given(build_handler, message_bus, recording_callback):
    handler = build_handler(
        event_processors={"orders": OrderUuidProcessor(event_name="custom-name")},
        callbacks=[recording_callback],
    )

    handler.handle_event(message_bus, Event("orders", None, b""))

    assert recording_callback.event_names[0] == "custom-name"
