package com.mobify.astro.utilities;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Locale;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(AndroidJUnit4.class)
public class LocalizationUtilitiesTest {

    private Context context;

    public static class StubLocaleChangedListener implements LocaleChangedListener {
        public int callCount = 0;

        @Override
        public void localeDidChange() {
            callCount++;
        }
    }

    private StubLocaleChangedListener stubLocaleChangedListener;
    private LocalizationUtilities localizationUtilities;

    @Before
    public void setUp() {
        stubLocaleChangedListener = new StubLocaleChangedListener();
        localizationUtilities = new LocalizationUtilities(InstrumentationRegistry.getTargetContext());
        localizationUtilities.addLocaleChangedListener(stubLocaleChangedListener);
        context = InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void testGetsNoChange() {
        assertNotNull(localizationUtilities.getLanguage());
        assertNotNull(localizationUtilities.getCountry());
        assertNotNull(localizationUtilities.getLocale());
        assertEquals(0, stubLocaleChangedListener.callCount);
    }

    @Test
    public void testSetLanguage() {
        localizationUtilities.setLanguage("ar");
        assertEquals("ar", localizationUtilities.getLanguage());
        assertEquals(1, stubLocaleChangedListener.callCount);
    }

    @Test
    public void testSetCountry() {
        localizationUtilities.setCountry("om");
        // Android Locale normalizes country codes to uppercase: https://developer.android.com/reference/java/util/Locale.html
        assertEquals("OM", localizationUtilities.getCountry());
        assertEquals(1, stubLocaleChangedListener.callCount);
    }

    @Test
    public void testSetLocale() {
        localizationUtilities.setLocale(new Locale("en", "ca"));
        assertEquals("en", localizationUtilities.getLanguage());
        // Android Locale normalizes country codes to uppercase: https://developer.android.com/reference/java/util/Locale.html
        assertEquals("CA", localizationUtilities.getCountry());
        Locale retrievedLocale = localizationUtilities.getLocale();
        assertEquals("en", retrievedLocale.getLanguage());
        assertEquals("CA", retrievedLocale.getCountry());
        assertEquals(1, stubLocaleChangedListener.callCount);
    }

    @Test
    public void testTranslate() {
        localizationUtilities.setLanguage("en");
        assertEquals("Basic test result", localizationUtilities.translate("test_basic"));
        localizationUtilities.setLanguage("ar");
        assertEquals("Basic test result (العربية)", localizationUtilities.translate("test_basic"));
        assertEquals(2, stubLocaleChangedListener.callCount);
    }

    @Test
    public void testTranslateInvalidLanguage() {
        localizationUtilities.setLanguage("zz");
        // Fall back to english if language is invalid
        assertEquals("Basic test result", localizationUtilities.translate("test_basic"));
        assertEquals(1, stubLocaleChangedListener.callCount);
    }

    // Translation key exists but not in the current language. Fall back to default.
    @Test
    public void testTranslateKeyDefault() {
        localizationUtilities.setLanguage("ar");
        assertEquals("Key only in base language", localizationUtilities.translate("test_default_only"));
        assertEquals(1, stubLocaleChangedListener.callCount);
    }

    // Key doesn't exist in dictionary, key returned
    @Test
    public void testTranslateInvalidKey() {
        assertEquals("junk_test_key", localizationUtilities.translate("junk_test_key"));
        assertEquals(0, stubLocaleChangedListener.callCount);
    }

    // New context with persisted locale is returned
    @Test
    public void testUpdateContextWithCurrentLocalization() {
        String localizationFileKey = context.getPackageName() + "." + LocalizationUtilities.LOCALIZATION_FILE_KEY_SUFFIX;
        SharedPreferences sharedPref = context.getSharedPreferences(localizationFileKey, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        Locale AR_LOCALE = new Locale("ar","SA");
        editor.putString(LocalizationUtilities.LANGUAGE_KEY, AR_LOCALE.getLanguage());
        editor.putString(LocalizationUtilities.COUNTRY_KEY, AR_LOCALE.getCountry());
        editor.apply();

        Context contextWithUpdatedLocale = LocalizationUtilities.updateContextWithCurrentLocalization(context);
        assertEquals(contextWithUpdatedLocale.getResources().getConfiguration().locale, AR_LOCALE);
    }
}
