import json
from typing import Dict

from messagebus import Event, HttpResponseMessage, Message
from messagebusmock import MessageBusSpy
from httpmessageprocessorutil.automapped import AutoMappedMessageProcessor
from testdoubleutil import SpyCall


class ParameterInteractor(object):
    def __init__(self):
        self.execute_call = SpyCall()

    def execute(self, obj):
        self.execute_call.register_call(obj)


msg_bus = MessageBusSpy()
msg = Message(0)


class TestFormatResponse(object):
    def test_SuccessStatusIsReplied(self):
        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus, msg, None, None, None)

        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].status_code == 200

    def test_WhenNoneIsReceived_NoneIsSentInTheBody(self):
        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus, msg, None, None, None)

        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].body is None

    def test_TheResponseObjectIsFormattedAsJson(self):
        class MyType(object):
            def __init__(self, id: int, name: str, value: float):
                self.id = id
                self.name = name
                self.value = value

        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus,
                                                                       msg,
                                                                       None,
                                                                       None,
                                                                       MyType(1, "name", 1.5))

        expected_value = json.dumps({
            "id": 1,
            "name": "name",
            "value": 1.5
        })
        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].body == expected_value

    def test_ThePropertiesAreConvertedToCamelCase(self):
        class MyType(object):
            def __init__(self, property_id: int, property_name: str, big_old_snake_case_name: str):
                self.property_id = property_id
                self.property_name = property_name
                self.big_old_snake_case_name = big_old_snake_case_name

        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus,
                                                                       msg,
                                                                       None,
                                                                       None,
                                                                       MyType(1,
                                                                              "name",
                                                                              "snakeCase"))

        expected_value = json.dumps({
            "propertyId": 1,
            "propertyName": "name",
            "bigOldSnakeCaseName": "snakeCase",
        })
        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].body == expected_value

    def test_KeysFromDictPropertiesAreNotConvertedToCamelCase(self):
        class MyType(object):
            def __init__(self, property_id: int, my_dict: Dict[str, str]):
                self.property_id = property_id
                self.my_dict = my_dict

        value = MyType(1, {
            "customer_name": "Customer Name",
            "customer_document": "customer_document",
            "my_key": MyType(1, {"customer_name": "Customer Name"})
        })

        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus, msg, None, None, value)

        expected_value = json.dumps({
            "propertyId": 1,
            "myDict": {
                "customer_name": "Customer Name",
                "customer_document": "customer_document",
                "my_key": {"propertyId": 1, "myDict": {"customer_name": "Customer Name"}}
            }
        })
        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].body == expected_value

    def test_InnerObjectsAreAlsoSerialized(self):
        class MyType2(object):
            def __init__(self, prop_1: int, prop_2: str, prop_3: float):
                self.prop_1 = prop_1
                self.prop_2 = prop_2
                self.prop_3 = prop_3

        class MyType(object):
            def __init__(self, property_id: int, property_second: MyType2):
                self.property_id = property_id
                self.property_second = property_second

        value = MyType(1, MyType2(1, "2", 3.5))

        AutoMappedMessageProcessor(str,
                                   ParameterInteractor(),
                                   success_status=200).format_response(msg_bus, msg, None, None, value)

        expected_value = json.dumps({
            "propertyId": 1,
            "propertySecond": {
                "prop1": 1,
                "prop2": "2",
                "prop3": 3.5
            }
        })
        assert isinstance(msg_bus.reply_message_call.args[1], HttpResponseMessage)
        assert msg_bus.reply_message_call.args[1].body == expected_value
