package com.mobify.astro.messaging;

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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

public class RpcResponseTest {

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

    @Before
    public void setup() throws Exception {
        testResponse = new RpcResponse("TestAddress", sender, "1");
        spyMessageSender = spy(new MessageSender(new EventManager()));
    }

    @Test
    public void testSetResult() throws JSONException {
        testResponse.setResult("TestString");
        assertEquals("TestString", testResponse.getPayload().get(RpcResponse.KeyNames.RESULT));
    }

    @Test
    public void testSetError() throws JSONException, NoSuchMethodException {
        Exception exception = new Exceptions.AnnotationArityMismatch(this.getClass().getMethod("testSetError"), 2);
        testResponse.setError(exception);

        JSONObject errorPayload = testResponse.getPayload().getJSONObject(RpcResponse.KeyNames.ERROR);
        assertTrue(errorPayload.getString(RpcResponse.KeyNames.ERROR_MESSAGE).contains("AnnotationArityMismatch"));
        assertTrue(errorPayload.getString(RpcResponse.KeyNames.ERROR_MESSAGE).contains("2"));
        assertTrue(errorPayload.getString(RpcResponse.KeyNames.ERROR_DETAILS).contains("none"));
        assertNotNull(errorPayload.get(RpcResponse.KeyNames.ERROR_STACK_TRACE));

        Object resultPayload = testResponse.getPayload().get(RpcResponse.KeyNames.RESULT);
        assertEquals(JSONObject.NULL, resultPayload);
    }

    @Test
    public void testSendObject() throws Exception {
        RpcResponse spyResponse = spy(testResponse);

        JSONObject result = new JSONObject("{\"foo\":\"bar\"}");

        spyMessageSender.sendRpcResponseWithResult(spyResponse, result);

        JSONObject retrievedResult = spyResponse.getPayload().getJSONObject(RpcResponse.KeyNames.RESULT);
        assertEquals(result, retrievedResult);

        verify(spyMessageSender).sendRpcResponseWithResult(spyResponse, result);
    }

    @Test
    public void testSent() {
        assertFalse(testResponse.isSent());
        testResponse.responseSent();
        assertTrue(testResponse.isSent());

        // Verify that this doesn't toggle
        testResponse.responseSent();
        assertTrue(testResponse.isSent());
    }

    @Test
    public void testGetDestinationAddress() {
        assertEquals("TestAddress", testResponse.getDestinationAddress());
    }
}
