package com.mobify.astro.utilities;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Locale;

public class LocalizationUtilities {

    private final static String TAG = LocalizationUtilities.class.getName();
    protected final static String LANGUAGE_KEY = "astro:localization:country";
    protected final static String COUNTRY_KEY = "astro:localization:language";
    protected final static String LOCALIZATION_FILE_KEY_SUFFIX = "LOCALIZATION";

    // Need to maintain an instance variable of the config because if we try to always access
    // the config from the context instance variable the left to right swapping does not work correctly
    private Configuration config = null;
    private SharedPreferences.Editor sharedPreferencesEditor = null;
    private Locale locale = null;
    private Context context = null;
    private ArrayList<WeakReference<LocaleChangedListener>> localeChangedListeners = new ArrayList<>();

    private boolean initialIsRightToLeft;

    public LocalizationUtilities(Context context) {
        this.context = context;
        config = context.getResources().getConfiguration();

        String localizationFileKey = context.getPackageName() + "." + LOCALIZATION_FILE_KEY_SUFFIX;
        SharedPreferences sharedPreferences = context.getSharedPreferences(localizationFileKey, Context.MODE_PRIVATE);
        this.sharedPreferencesEditor = sharedPreferences.edit();

        String language = sharedPreferences.getString(LANGUAGE_KEY, config.locale.getLanguage());
        String country = sharedPreferences.getString(COUNTRY_KEY, config.locale.getCountry());
        updateContextAndConfigWithLocale(new Locale(language, country));

        initialIsRightToLeft = rightToLeft();
    }

    // Takes app's context, and creates a new context with the locale persisted by LocalizationUtilities
    public static Context updateContextWithCurrentLocalization(Context context) {
        String localizationFileKey = context.getPackageName() + "." + LOCALIZATION_FILE_KEY_SUFFIX;
        SharedPreferences sharedPreferences = context.getSharedPreferences(localizationFileKey, Context.MODE_PRIVATE);

        Configuration config = context.getResources().getConfiguration();
        String language = sharedPreferences.getString(LANGUAGE_KEY, config.locale.getLanguage());
        String country = sharedPreferences.getString(COUNTRY_KEY, config.locale.getCountry());
        Locale locale = new Locale(language, country);

        Locale.setDefault(locale);
        config.setLocale(locale);
        config.setLayoutDirection(locale);
        return context.createConfigurationContext(config);
    }

    // Updates the context and config instance variables with the new locale
    private void updateContextAndConfigWithLocale(Locale locale) {
        this.locale = locale;
        config.setLocale(locale);
        context = context.createConfigurationContext(config);
    }

    // Updates the instance variable context and config with new locale, and
    // saves the new configuration to SharedPreferences and update all UI.
    private void updateConfigurationLocale(Locale locale) {
        updateContextAndConfigWithLocale(locale);

        sharedPreferencesEditor.putString(LANGUAGE_KEY, locale.getLanguage());
        sharedPreferencesEditor.putString(COUNTRY_KEY, locale.getCountry());
        sharedPreferencesEditor.apply();

        for (WeakReference<LocaleChangedListener> listenerReference: localeChangedListeners) {
            LocaleChangedListener localeChangedListener = listenerReference.get();
            if (localeChangedListener != null) {
                localeChangedListener.localeDidChange();
            }
        }
    }

    public void addLocaleChangedListener(LocaleChangedListener listener) {
        localeChangedListeners.add(new WeakReference<>(listener));
    }

    public String getLanguage() {
        return locale.getLanguage();
    }

    public void setLanguage(String language) {
        updateConfigurationLocale(new Locale(language, locale.getCountry()));
    }

    public String getCountry() {
        return locale.getCountry();
    }

    public void setCountry(String country) {
        updateConfigurationLocale(new Locale(locale.getLanguage(), country));
    }

    public Locale getLocale() {
        return locale;
    }

    public void setLocale(Locale locale) {
        updateConfigurationLocale(locale);
    }

    public String translate(String key) {
        int resId = context.getResources().getIdentifier(key, "string", context.getPackageName());
        try {
            return context.getString(resId);
        } catch (Resources.NotFoundException e) {
            Log.e(TAG, "Failed to lookup translation for key: " + key);
            return key;
        }
    }

    public boolean leftToRight() {
        return config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
    }

    public boolean rightToLeft() {
        return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
    }

    // Although not used in Astro/Sandbox, this is utilized in DoubleIconsPlugin in Extra
    public boolean initialRightToLeft() {
        return initialIsRightToLeft;
    }
}
