package com.tencent.qcloud.tuicore;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.webkit.WebView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.tencent.qcloud.tuicore.util.SPUtils;
import com.tencent.qcloud.tuicore.util.TUIBuild;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Static skinning, language
 */
public class TUIThemeManager {
    private static final String TAG = TUIThemeManager.class.getSimpleName();

    private static final String SP_THEME_AND_LANGUAGE_NAME = "TUIThemeAndLanguage";
    private static final String SP_KEY_LANGUAGE = "language";
    private static final String SP_KEY_THEME = "theme";
    private static final String SP_KEY_ENABLE_CHANGE_LANGUAGE = "enable_change_language";

    public static final int THEME_LIGHT = 0; // default
    public static final int THEME_LIVELY = 1;
    public static final int THEME_SERIOUS = 2;

    public static final String LANGUAGE_ZH_CN = "zh";
    public static final String LANGUAGE_ZH_HK = "zh-traditional";
    public static final String LANGUAGE_EN = "en";
    public static final String LANGUAGE_AR = "ar";

    private static final class ThemeManagerHolder {
        private static final TUIThemeManager instance = new TUIThemeManager();
    }

    public static TUIThemeManager getInstance() {
        return ThemeManagerHolder.instance;
    }

    private boolean isInit = false;

    private final Map<Integer, List<Integer>> themeResIDMap = new HashMap<>();
    private final Map<String, Locale> languageMap = new HashMap<>();

    private int currentThemeID = THEME_LIGHT;
    private String currentLanguage = "";
    private Locale defaultLocale = null;
    private boolean enableLanguageSwitch = false;

    private TUIThemeManager() {
        languageMap.put(LANGUAGE_ZH_CN, Locale.CHINESE);
        languageMap.put(LANGUAGE_ZH_HK, Locale.TRADITIONAL_CHINESE);
        languageMap.put(LANGUAGE_EN, Locale.ENGLISH);
        languageMap.put(LANGUAGE_AR, new Locale("ar"));
    }

    public static void setTheme(Context context) {
        getInstance().setThemeInternal(context);
    }

    public static void setEnableLanguageSwitch(boolean enableLanguageSwitch) {
        getInstance().enableLanguageSwitch = enableLanguageSwitch;
        SPUtils spUtils = SPUtils.getInstance(SP_THEME_AND_LANGUAGE_NAME);
        spUtils.put(SP_KEY_ENABLE_CHANGE_LANGUAGE, enableLanguageSwitch);
    }

    private void setThemeInternal(Context context) {
        if (context == null) {
            return;
        }

        Context appContext = context.getApplicationContext();
        if (!isInit) {
            isInit = true;
            SPUtils spUtils = SPUtils.getInstance(SP_THEME_AND_LANGUAGE_NAME);
            enableLanguageSwitch = spUtils.getBoolean(SP_KEY_ENABLE_CHANGE_LANGUAGE, false);

            if (appContext instanceof Application) {
                ((Application) appContext).registerActivityLifecycleCallbacks(new ThemeAndLanguageCallback());
            }

            notifySetLanguageEvent();
            Locale defaultLocale = getLocale(appContext);
            currentLanguage = spUtils.getString(SP_KEY_LANGUAGE, defaultLocale.getLanguage());
            currentThemeID = spUtils.getInt(SP_KEY_THEME, THEME_LIGHT);

            // The language only needs to be initialized once
            applyLanguage(appContext);
        }
        // The theme needs to be updated multiple times
        applyTheme(appContext);
    }

    private static String currentProcessName = "";

    public static String getProcessName() {
        if (!TextUtils.isEmpty(currentProcessName)) {
            return currentProcessName;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            currentProcessName = Application.getProcessName();
            return currentProcessName;
        }

        try {
            final Method declaredMethod = Class.forName("android.app.ActivityThread", false, Application.class.getClassLoader())
                                              .getDeclaredMethod("currentProcessName", (Class<?>[]) new Class[0]);
            declaredMethod.setAccessible(true);
            final Object invoke = declaredMethod.invoke(null, new Object[0]);
            if (invoke instanceof String) {
                currentProcessName = (String) invoke;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return currentProcessName;
    }

    private void notifySetLanguageEvent() {
        TUICore.notifyEvent(TUIConstants.TUICore.LANGUAGE_EVENT, TUIConstants.TUICore.LANGUAGE_EVENT_SUB_KEY, null);
    }

    /**
     * Solve the problem that WebView on Android 7 and above causes failure to switch languages.
     * Solve the problem of using WebView Crash for multiple processes above Android 9.
     */
    public static void setWebViewLanguage(Context appContext) {
        try {
            Log.i(TAG, "setWebViewLanguage");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                WebView.setDataDirectorySuffix(getProcessName());
            }
            new WebView(appContext).destroy();
        } catch (Throwable throwable) {
            Log.e("TUIThemeManager", "init language settings failed, " + throwable.getMessage());
        }
    }

    public void setDefaultLocale(Locale defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    public static void addTheme(int themeID, int resID) {
        if (resID == 0) {
            Log.e(TAG, "addTheme failed, theme resID is zero");
            return;
        }
        Log.i(TAG, "addTheme themeID=" + themeID + " resID=" + resID);
        List<Integer> themeResIDList = getInstance().themeResIDMap.get(themeID);
        if (themeResIDList == null) {
            themeResIDList = new ArrayList<>();
            getInstance().themeResIDMap.put(themeID, themeResIDList);
        }
        if (themeResIDList.contains(resID)) {
            return;
        }
        themeResIDList.add(resID);
        TUIThemeManager.getInstance().applyTheme(ServiceInitializer.getAppContext());
    }

    public static void addLightTheme(int resId) {
        addTheme(THEME_LIGHT, resId);
    }

    public static void addLivelyTheme(int resId) {
        addTheme(THEME_LIVELY, resId);
    }

    public static void addSeriousTheme(int resId) {
        addTheme(THEME_SERIOUS, resId);
    }

    public int getCurrentTheme() {
        return currentThemeID;
    }

    private void mergeTheme(Resources.Theme theme) {
        if (theme == null) {
            return;
        }

        List<Integer> currentThemeResIDList = themeResIDMap.get(currentThemeID);
        if (currentThemeResIDList == null) {
            return;
        }
        for (Integer resId : currentThemeResIDList) {
            theme.applyStyle(resId, true);
        }
    }

    public static void addLanguage(String language, Locale locale) {
        Log.i(TAG, "addLanguage language=" + language + " locale=" + locale);
        getInstance().languageMap.put(language, locale);
    }

    public void changeLanguage(Context context, String language) {
        if (context == null) {
            return;
        }

        if (TextUtils.equals(language, currentLanguage)) {
            return;
        }
        setEnableLanguageSwitch(true);
        currentLanguage = language;
        SPUtils spUtils = SPUtils.getInstance(SP_THEME_AND_LANGUAGE_NAME);
        spUtils.put(SP_KEY_LANGUAGE, language, true);

        applyLanguage(context.getApplicationContext());
        applyLanguage(context);

        TUICore.notifyEvent(TUIConstants.TUICore.LANGUAGE_EVENT, TUIConstants.TUICore.LANGUAGE_CHANGED_EVENT_SUB_KEY, null);
    }

    public void applyLanguage(Context context) {
        if (!enableLanguageSwitch) {
            return;
        }
        if (context == null) {
            return;
        }
        Locale locale = languageMap.get(currentLanguage);
        if (locale == null) {
            if (defaultLocale != null) {
                locale = defaultLocale;
            } else {
                locale = getLocale(context);
            }
        }

        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        configuration.setLocale(locale);
        resources.updateConfiguration(configuration, null);

        if (Build.VERSION.SDK_INT >= 25) {
            context = context.createConfigurationContext(configuration);
            context.getResources().updateConfiguration(configuration, resources.getDisplayMetrics());
        }
    }

    public String getCurrentLanguage() {
        return currentLanguage;
    }

    public Locale getLocale(Context context) {
        Locale locale;

        if (TUIBuild.getVersionInt() < Build.VERSION_CODES.N) {
            locale = context.getResources().getConfiguration().locale;
        } else {
            locale = context.getResources().getConfiguration().getLocales().get(0);
        }
        return locale;
    }

    public void changeTheme(Context context, int themeId) {
        if (context == null) {
            return;
        }

        if (themeId == currentThemeID) {
            return;
        }
        currentThemeID = themeId;

        SPUtils spUtils = SPUtils.getInstance(SP_THEME_AND_LANGUAGE_NAME);
        spUtils.put(SP_KEY_THEME, themeId, true);

        applyTheme(context.getApplicationContext());
        applyTheme(context);
    }

    private void applyTheme(Context context) {
        if (context == null) {
            return;
        }
        Resources.Theme theme = context.getTheme();
        if (theme == null) {
            context.setTheme(R.style.TUIBaseTheme);
            theme = context.getTheme();
        }
        mergeTheme(theme);
    }

    /**
     * Get resources for skinning
     *
     * @param context   context
     * @param attrId    custom attribute
     * @return resources for skinning
     */
    public static int getAttrResId(Context context, int attrId) {
        if (context == null || attrId == 0) {
            return 0;
        }
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrId, typedValue, true);
        return typedValue.resourceId;
    }

    static class ThemeAndLanguageCallback implements Application.ActivityLifecycleCallbacks {
        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
            TUIThemeManager.getInstance().applyTheme(activity);
            TUIThemeManager.getInstance().applyLanguage(activity);
            TUIThemeManager.getInstance().applyLanguage(activity.getApplicationContext());
        }

        @Override
        public void onActivityStarted(@NonNull Activity activity) {}

        @Override
        public void onActivityResumed(@NonNull Activity activity) {}

        @Override
        public void onActivityPaused(@NonNull Activity activity) {}

        @Override
        public void onActivityStopped(@NonNull Activity activity) {}

        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {}
    }
}
