package com.mobify.astro.messaging;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;

import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

public class MessageSenderTest {

    private EventManager mockEventManager;
    private MessageSender messageSender;

    private AddressableObject sender = new AddressableObject() {
        @Override
        public String getInstanceAddress() {
            return String.format("%s:%d", this.getClass().getName(), this.hashCode());
        }
    };

    @Before
    public void setup() throws Exception {
        mockEventManager = mock(EventManager.class);
        messageSender = new MessageSender(mockEventManager);
    }

    @Test
    public void testSendMessageToAddress() throws JSONException {
        Message message = new Message(new JSONObject("{\"header\": \"test header\", \"payload\": {\"key\": \"value\"}}"));
        messageSender.sendMessageToAddress(message, "someAddress:1234");
        verify(mockEventManager, times(1)).trigger(eq("someAddress:1234"), any(JSONObject.class));
    }

    @Test
    public void testSendMessageToAddressCatchesHeaderSerializationException() throws JSONException {
        Message message = new Message(new JSONObject("{\"header\": \"test header\", \"payload\": {\"key\": \"value\"}}"));
        message.setHeader(null, "foo");
        messageSender.sendMessageToAddress(message, "someAddress:1234");
        verify(mockEventManager, never()).trigger(any(String.class), any(JSONObject.class));
    }

    @Test
    public void testSendRpcResponse() throws JSONException {
        RpcResponse testResponse = new RpcResponse("TestAddress", sender, "1");
        messageSender.sendRpcResponse(testResponse);
        verify(mockEventManager, times(1)).trigger(eq("TestAddress"), any(JSONObject.class));
        assertTrue(testResponse.isSent());
    }

    @Test
    public void testSendRpcResponseWithResult() throws JSONException {
        RpcResponse testResponse = spy(new RpcResponse("TestAddress", sender, "1"));
        messageSender.sendRpcResponseWithResult(testResponse, "MyResult");
        verify(testResponse, times(1)).setResult("MyResult");
        verify(mockEventManager, times(1)).trigger(eq("TestAddress"), any(JSONObject.class));
        assertTrue(testResponse.isSent());
    }

    @Test
    public void testSendRpcResponseWithError() throws JSONException, NoSuchMethodException {
        Exception exception = new Exceptions.AnnotationArityMismatch(this.getClass().getMethod("testSendRpcResponseWithError"), 2);
        RpcResponse testResponse = spy(new RpcResponse("TestAddress", sender, "1"));
        messageSender.sendRpcResponseWithError(testResponse, exception);
        verify(testResponse, times(1)).setError(exception);
        verify(mockEventManager, times(1)).trigger(eq("TestAddress"), any(JSONObject.class));
        assertTrue(testResponse.isSent());
    }
}
