package com.mobify.astro.plugins.webviewplugin;

import android.support.annotation.NonNull;
import android.webkit.WebView;

import com.mobify.astro.ActivityTestBase;
import com.mobify.astro.AstroActivity;
import com.mobify.astro.PluginResolver;
import com.mobify.astro.messaging.EventManager;
import com.mobify.astro.messaging.JsonMessageFactory;
import com.mobify.astro.messaging.Message;
import com.mobify.astro.messaging.MessageSender;

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.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

public class AstroWebViewPluginTest extends ActivityTestBase {

    private TestWebViewPlugin testWebViewPlugin;

    // Must be publicly accessibly so that tests can spy on it
    public class TestWebViewPlugin extends AstroWebViewPlugin {
        WebView webView;

        TestWebViewPlugin(@NonNull AstroActivity activity, @NonNull PluginResolver pluginResolver,
                          @NonNull EventManager eventManager, @NonNull MessageSender messageSender) {
            super(activity, pluginResolver, eventManager, messageSender);
        }

        @Override
        public WebView getWebView() {
            return webView;
        }
    }

    @Before
    public void setup() {
        PluginResolver mockPluginResolver = mock(PluginResolver.class);
        EventManager mockEventManager = mock(EventManager.class);
        MessageSender mockMessageSender = mock(MessageSender.class);
        testWebViewPlugin = spy(new TestWebViewPlugin(getActivity(), mockPluginResolver, mockEventManager, mockMessageSender));
    }

    @Test
    public void testMessageIsForJs() throws Exception {
        JSONObject json = new JSONObject("{\"payload\":{\"eventName\":\"someEvent\"}}");
        Message message = JsonMessageFactory.fromJSON(json);

        boolean isForJs = testWebViewPlugin.messageIsForJs(message);
        assertTrue(isForJs);
    }

    @Test
    public void testTransformNativeAddressToJs() throws Exception {
        String transformedAddress;
        String instanceAddress = testWebViewPlugin.getInstanceAddress();

        transformedAddress = testWebViewPlugin.transformNativeAddressToJs(instanceAddress);
        assertEquals(TestWebViewPlugin.SELF_KEYWORD, transformedAddress);
        transformedAddress = testWebViewPlugin.transformNativeAddressToJs(instanceAddress + ":yaaaahbuddy");
        assertEquals(TestWebViewPlugin.SELF_KEYWORD + ":yaaaahbuddy", transformedAddress);

        transformedAddress = testWebViewPlugin.transformNativeAddressToJs("123");
        assertEquals("123", transformedAddress);
        transformedAddress = testWebViewPlugin.transformNativeAddressToJs("123:events");
        assertEquals("123:events", transformedAddress);
    }

    @Test
    public void testTransformJsAddressToNative() throws Exception {
        String transformedAddress;
        String instanceAddress = testWebViewPlugin.getInstanceAddress();

        transformedAddress = testWebViewPlugin.transformJsAddressToNative(TestWebViewPlugin.SELF_KEYWORD);
        assertEquals(instanceAddress, transformedAddress);
        transformedAddress = testWebViewPlugin.transformJsAddressToNative(TestWebViewPlugin.SELF_KEYWORD + ":yaaaahbuddy");
        assertEquals(instanceAddress + ":yaaaahbuddy", transformedAddress);

        transformedAddress = testWebViewPlugin.transformJsAddressToNative("123");
        assertEquals("123", transformedAddress);
        transformedAddress = testWebViewPlugin.transformJsAddressToNative("123:events");
        assertEquals("123:events", transformedAddress);
    }

    @Test
    public void testSetJsLoaded() throws Exception {
        testWebViewPlugin.setJsLoaded(false);
        assertFalse(testWebViewPlugin.isJsLoaded);
        verify(testWebViewPlugin, never()).flushJsQueue();

        testWebViewPlugin.setJsLoaded(true);
        assertTrue(testWebViewPlugin.isJsLoaded);
        verify(testWebViewPlugin).flushJsQueue();
    }

    @Test
    public void testInvokeJavaScript() throws Exception {
        testWebViewPlugin.webView = mock(WebView.class);
        testWebViewPlugin.setJsLoaded(true);

        assertEquals(testWebViewPlugin.jsQueue.size(), 0);

        testWebViewPlugin.invokeJavaScript("1 + 1");
        verify(testWebViewPlugin.webView).evaluateJavascript("1 + 1", null);

        testWebViewPlugin.invokeJavaScript("alert('HANDSTANDS LIKE PIZZA!')");
        verify(testWebViewPlugin.webView).evaluateJavascript("alert('HANDSTANDS LIKE PIZZA!')", null);

        assertEquals(testWebViewPlugin.jsQueue.size(), 0);
    }

    @Test
    public void testInvokeJavaScriptQueues() throws Exception {
        testWebViewPlugin.setJsLoaded(false);

        assertEquals(testWebViewPlugin.jsQueue.size(), 0);
        testWebViewPlugin.invokeJavaScript("1 + 1");
        testWebViewPlugin.invokeJavaScript("alert('nah')");
        assertEquals(testWebViewPlugin.jsQueue.size(), 2);
    }

    @Test
    public void testFlushJsQueue() throws Exception {
        testWebViewPlugin.webView = mock(WebView.class);
        testWebViewPlugin.setJsLoaded(false);

        testWebViewPlugin.jsQueue.add("1 + 2");
        testWebViewPlugin.jsQueue.add("alert('hah')");
        testWebViewPlugin.setJsLoaded(true);

        assertEquals(testWebViewPlugin.jsQueue.size(), 0);
        verify(testWebViewPlugin).invokeJavaScript("1 + 2");
        verify(testWebViewPlugin).invokeJavaScript("alert('hah')");

    }
}
