package com.mobify.astro.plugins;

import android.content.Context;
import android.content.SharedPreferences;

import com.mobify.astro.ActivityTestBase;
import com.mobify.astro.AstroActivity;
import com.mobify.astro.PluginResolver;
import com.mobify.astro.helpers.RandomStringGenerator;
import com.mobify.astro.messaging.EventManager;
import com.mobify.astro.messaging.MessageSender;

import org.junit.Before;
import org.junit.Test;

import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;

public class SecureStorePluginTest extends ActivityTestBase {
    private final static String SECURE_STORE_FILE_KEY = "com.mobify.astro.SECURE_STORAGE";

    private SecureStorePlugin secureStorePlugin;
    private SharedPreferences sharedPref;

    @Before
    public void setup() throws Throwable {
        PluginResolver mockPluginResolver = mock(PluginResolver.class);
        EventManager mockEventManager = mock(EventManager.class);
        MessageSender mockMessageSender = mock(MessageSender.class);

        AstroActivity activity = getActivity();

        secureStorePlugin = new SecureStorePlugin(activity, mockPluginResolver, mockEventManager, mockMessageSender);

        sharedPref = activity.getSharedPreferences(SECURE_STORE_FILE_KEY, Context.MODE_PRIVATE);
        sharedPref.edit().clear().apply();
    }

    private int getNumberOfKeys() {
        Map<String, ?> keys =  sharedPref.getAll();
        return keys.size();
    }

    @Test
    public void testSetReplace() throws Exception{
        assertNull(secureStorePlugin.get("some key"));

        secureStorePlugin.set("some key", "some value");
        assertEquals("some value", secureStorePlugin.get("some key"));

        secureStorePlugin.set("some key", "some value 2");
        assertEquals("some value 2", secureStorePlugin.get("some key"));
        assertEquals(1, getNumberOfKeys());
    }

    @Test
    public void testSetMultipleKeys() throws Exception {
        assertNull(secureStorePlugin.get("some key"));

        secureStorePlugin.set("some key", "some value");
        assertEquals("some value", secureStorePlugin.get("some key"));
        assertEquals(1, getNumberOfKeys());

        secureStorePlugin.set("some key 2", "some value 2");
        assertEquals("some value 2", secureStorePlugin.get("some key 2"));
        assertEquals(2, getNumberOfKeys());

        secureStorePlugin.set("some key 3", "some value 3");
        assertEquals("some value 3", secureStorePlugin.get("some key 3"));
        assertEquals(3, getNumberOfKeys());
    }

    @Test
    public void testSetLargeValue()  throws Exception {
        String largeValue = RandomStringGenerator.generate(512);
        secureStorePlugin.set("long value key", largeValue);
        assertEquals(largeValue, secureStorePlugin.get("long value key"));
        assertEquals(1, getNumberOfKeys());
    }

    @Test
    public void testGetEmptyStringKey() {
        try {
            secureStorePlugin.get("");
            fail("This should throw an Exception");
        } catch (Exception e) {
            assertEquals(SecureStorePlugin.SecureStorePluginException.class, e.getClass());
        }
    }

    @Test
    public void testSetEmptyStringKey() {
        try{
            secureStorePlugin.set("", "some value");
            fail("This should throw an Exception");
        } catch (Exception e) {
            assertEquals(SecureStorePlugin.SecureStorePluginException.class, e.getClass());
        }
    }

    @Test
    public void testGetNullKey() {
        try {
            secureStorePlugin.get(null);
            fail("This should throw an Exception");
        } catch (Exception e) {
            assertEquals(SecureStorePlugin.SecureStorePluginException.class, e.getClass());
        }
    }

    @Test
    public void testSetNullKey() {
        try{
            secureStorePlugin.set(null, "some value");
            fail("This should throw an Exception");
        } catch (Exception e) {
            assertEquals(SecureStorePlugin.SecureStorePluginException.class, e.getClass());
        }
    }

    @Test
    public void testSetNullValue() {
        try{
            secureStorePlugin.set("some key", null);
            fail("This should throw an Exception");
        } catch (Exception e) {
            assertEquals(SecureStorePlugin.SecureStorePluginException.class, e.getClass());
        }
    }

    @Test
    public void testSetEmptyValue() throws Exception {
        secureStorePlugin.set("some key", "");
        assertEquals("", secureStorePlugin.get("some key"));
        assertEquals(1, getNumberOfKeys());
    }

    @Test
    public void testDelete() throws Exception {
        secureStorePlugin.set("some key 1", "some value 1");
        secureStorePlugin.set("some key 2", "some value 2");

        assertEquals("some value 1", secureStorePlugin.get("some key 1"));
        assertEquals("some value 2", secureStorePlugin.get("some key 2"));

        secureStorePlugin.delete("some key 1");

        assertNull(secureStorePlugin.get("some key"));
        assertEquals("some value 2", secureStorePlugin.get("some key 2"));
        assertEquals(1, getNumberOfKeys());
    }

    @Test
    public void testClear() throws Exception {
        secureStorePlugin.set("some key 1", "some value 1");
        secureStorePlugin.set("some key 2", "some value 2");
        secureStorePlugin.set("some key 3", "some value 3");

        assertEquals("some value 1", secureStorePlugin.get("some key 1"));
        assertEquals("some value 2", secureStorePlugin.get("some key 2"));
        assertEquals("some value 3", secureStorePlugin.get("some key 3"));
        assertEquals(3, getNumberOfKeys());

        secureStorePlugin.clear();

        assertNull(secureStorePlugin.get("some key 1"));
        assertNull(secureStorePlugin.get("some key 2"));
        assertNull(secureStorePlugin.get("some key 3"));

        assertEquals(0, getNumberOfKeys());
    }
}
