package com.mobify.astro;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;

import com.mobify.astro.plugins.webviewplugin.AstroWebChromeClient;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

@RunWith(AndroidJUnit4.class)
public class PermissionsManagerTest extends ActivityTestBase {

    @Mock
    private PermissionsManager.PermissionsCallback callBack;
    private Activity activity;
    private PermissionsManager permissionsManager;
    private String[] permission;
    private String[] permissions;
    private int requestCode = AstroWebChromeClient.ACCESS_LOCATION_PERMISSION_REQUEST;

    @Rule
    public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.ACCESS_FINE_LOCATION);

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        activity = getActivity();
        permissionsManager = new PermissionsManager(activity);
        permission = new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION};
        permissions = new String [] {android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION};
    }

    // Tests if given requestCode pair is removed from PermissionsManager.permissionsCallbacks given a valid code
    @Test
    public void testHandleRequestPermissionsResultValidRequest() {
        int[] grantResults = new int[] {PackageManager.PERMISSION_GRANTED};
        permissionsManager.permissionsCallbacks.put(requestCode, callBack);

        boolean isValidCode = permissionsManager.handleRequestPermissionsResult(requestCode, permission, grantResults);

        verify(callBack).onPermissionUpdated(true);
        assert(permissionsManager.permissionsCallbacks.size() == 0);
        assertTrue(isValidCode);
    }

    // Tests if given requestCode pair is not removed from PermissionsManager.permissionsCallbacks given an invalid code
    @Test
    public void testHandleRequestPermissionsResultInvalidRequest() {
        int[] grantResults = new int[] {PackageManager.PERMISSION_GRANTED};
        int INVALID_REQUEST_CODE = -1;
        permissionsManager.permissionsCallbacks.put(requestCode, callBack);

        boolean isValidCode = permissionsManager.handleRequestPermissionsResult(INVALID_REQUEST_CODE, permission, grantResults);

        verify(callBack, never()).onPermissionUpdated(Mockito.anyBoolean());
        assert(permissionsManager.permissionsCallbacks.size() == 1);
        assertFalse(isValidCode);
    }

    // Tests if grant results containing all PERMISSION_GRANTED invokes callBack with `isPermissionGiven = true`
    @Test
    public void testHandleRequestPermissionsResultAllGranted() {
        int[] grantResults = new int[] {PackageManager.PERMISSION_GRANTED, PackageManager.PERMISSION_GRANTED};
        permissionsManager.permissionsCallbacks.put(requestCode, callBack);

        boolean isValidCode = permissionsManager.handleRequestPermissionsResult(requestCode, permissions, grantResults);

        verify(callBack).onPermissionUpdated(true);
        assert(permissionsManager.permissionsCallbacks.size() == 0);
        assertTrue(isValidCode);
    }

    // Tests if grant results containing a PERMISSION_DENIED invokes callBack with `isPermissionGiven = false`
    @Test
    public void testHandleRequestPermissionsResultDenied() {
        int[] grantResults = new int[] {PackageManager.PERMISSION_GRANTED, PackageManager.PERMISSION_DENIED};
        permissionsManager.permissionsCallbacks.put(requestCode, callBack);

        boolean isValidCode = permissionsManager.handleRequestPermissionsResult(requestCode, permissions, grantResults);

        verify(callBack).onPermissionUpdated(false);
        assert(permissionsManager.permissionsCallbacks.size() == 1);
        assertTrue(isValidCode);
    }

    // Tests if requestPermission invokes the saved callBack's onPermissionUpdated
    @Test
    public void testPermissionRequestWithPermission() {
        permissionsManager.permissionRequest(requestCode, permissions, callBack);
        verify(callBack).onPermissionUpdated(true);
        assert(permissionsManager.permissionsCallbacks.size() == 0);
    }
}
