package com.mobify.astro;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.test.runner.AndroidJUnit4;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

@RunWith(AndroidJUnit4.class)
public class DeepLinkHandlerTest {

    private DeepLinkHandler deepLinkHandler;
    private AstroApplication mockAstroApplication;
    private Context context;

    private Intent buildLaunchFromHistoryDeepLinkIntent() {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
        intent.setData(Uri.parse("testscheme:///http://www.test.ca"));

        return intent;
    }

    private Intent buildDeepLinkIntent() {
        Intent intent = new Intent();
        intent.setData(Uri.parse("testscheme:///http://www.test.ca"));

        return intent;
    }

    @Before
    public void initDeepLinkHandler() {
        context = mock(Context.class);
        mockAstroApplication = mock(AstroApplication.class);

        deepLinkHandler = new DeepLinkHandler(context, mockAstroApplication);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkTrueConsumedIntentTrue() {
        deepLinkHandler.setAppStartedWithDeepLink(true);
        deepLinkHandler.setConsumedIntent(true);

        deepLinkHandler.attemptDeepLinkHandling(new Intent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkFalseConsumedIntentTrueDeepLink() {
        deepLinkHandler.setAppStartedWithDeepLink(false);
        deepLinkHandler.setConsumedIntent(true);

        deepLinkHandler.attemptDeepLinkHandling(buildDeepLinkIntent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkFalseConsumedIntentTrueLaunchedFromHistory() {
        deepLinkHandler.setAppStartedWithDeepLink(false);
        deepLinkHandler.setConsumedIntent(true);

        deepLinkHandler.attemptDeepLinkHandling(buildLaunchFromHistoryDeepLinkIntent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkTrueConsumedIntentFalseEmptyIntent() {
        deepLinkHandler.setAppStartedWithDeepLink(true);
        deepLinkHandler.setConsumedIntent(false);

        deepLinkHandler.attemptDeepLinkHandling(new Intent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkTrueConsumedIntentFalseDeepLinkIntent() {
        deepLinkHandler.setAppStartedWithDeepLink(true);
        deepLinkHandler.setConsumedIntent(false);

        deepLinkHandler.attemptDeepLinkHandling(buildDeepLinkIntent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertThat(deepLinkHandler.getStartUri(), equalTo("http://www.test.ca"));
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }

    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkFalseConsumedIntentFalseDeepLinkIntent() throws JSONException {
        deepLinkHandler.setAppStartedWithDeepLink(false);
        deepLinkHandler.setConsumedIntent(false);

        deepLinkHandler.attemptDeepLinkHandling(buildDeepLinkIntent());

        ArgumentCaptor<JSONObject> argumentCaptorData = ArgumentCaptor.forClass(JSONObject.class);

        verify(mockAstroApplication).deepLink(argumentCaptorData.capture());

        JSONObject data = argumentCaptorData.getValue();
        assertTrue(data.has("uri"));

        String uri = data.getString("uri");
        assertThat(uri, equalTo("http://www.test.ca"));

        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }


    @Test
    public void attemptDeepLinkAppStartedWithDeepLinkFalseConsumedIntentFalseLaunchedFromHistory() {
        deepLinkHandler.setAppStartedWithDeepLink(false);
        deepLinkHandler.setConsumedIntent(false);

        deepLinkHandler.attemptDeepLinkHandling(buildLaunchFromHistoryDeepLinkIntent());

        verify(mockAstroApplication, never()).deepLink(any(JSONObject.class));
        verify(context, never()).sendBroadcast(any(Intent.class));
        assertNull(deepLinkHandler.getStartUri());
        assertNull(deepLinkHandler.pushNotificationsExtraFromStartup);
    }
}