package com.oasisfeng.nevo.decorators.wechat;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.TwoStatePreference;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StringRes;
import android.util.Log;

import com.oasisfeng.nevo.sdk.NevoDecoratorService;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.DONT_KILL_APP;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.N;
import static com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.TAG;
import static com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.WECHAT_PACKAGE;

/**
 * Entry activity. Some ROMs (including Samsung, OnePlus) require a launcher activity to allow any component being bound by other app.
 */
@SuppressWarnings("deprecation") @SuppressLint("ExportedPreferenceActivity")
public class WeChatDecoratorSettingsActivity extends PreferenceActivity {

	private static final int CURRENT_AGENT_VERSION = 1300;
	private static final String NEVOLUTION_PACKAGE = "com.oasisfeng.nevo";
	private static final String ANDROID_AUTO_PACKAGE = "com.google.android.projection.gearhead";
	private static final String AGENT_WECHAT_PACKAGE = "com.oasisfeng.nevo.agents.wechat";
	private static final String PLAY_STORE_PACKAGE = "com.android.vending";
    private static final String ISLAND_PACKAGE = "com.oasisfeng.island";
	private static final String APP_MARKET_PREFIX = "market://details?id=";

	@Override protected void onCreate(@Nullable final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		final PreferenceManager manager = getPreferenceManager();
		manager.setSharedPreferencesName(WeChatDecorator.PREFERENCES_NAME);
		if (SDK_INT >= N) manager.setStorageDeviceProtected();
		getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
		addPreferencesFromResource(R.xml.decorators_wechat_settings);
	}

	@Override protected void onResume() {
		super.onResume();
		final Preference preference_activate = findPreference(getString(R.string.pref_activate));
		boolean nevolution_installed = false, wechat_installed = false, running = false;
		final PackageManager pm = getPackageManager();
		try {
			pm.getApplicationInfo(NEVOLUTION_PACKAGE, 0);
			nevolution_installed = true;
			pm.getApplicationInfo(WECHAT_PACKAGE, PackageManager.GET_UNINSTALLED_PACKAGES);
			wechat_installed = true;
			running = isDecoratorRunning();
		} catch (final NameNotFoundException ignored) {}

		preference_activate.setEnabled(! nevolution_installed || wechat_installed);		// No reason to promote WeChat if not installed.
		preference_activate.setSelectable(! running);
		preference_activate.setSummary(! nevolution_installed ? getText(R.string.pref_activate_summary_nevo_not_installed)
				: ! wechat_installed ? getText(R.string.pref_activate_summary_wechat_not_installed)
				: running ? getText(R.string.pref_activate_summary_already_activated) : null);
		preference_activate.setOnPreferenceClickListener(! nevolution_installed ? this::installNevolution
				: wechat_installed && ! running ? this::activate : null);

		final Preference preference_extension = findPreference(getString(R.string.pref_extension));
		final boolean android_auto_available = getPackageVersion(ANDROID_AUTO_PACKAGE) >= 0;
		final List<Integer> android_auto_unavailable_in_profiles = new ArrayList<>();
		List<UserHandle> profiles = Collections.emptyList();
		if (SDK_INT >= N) {
			final UserManager um = getSystemService(UserManager.class);
			final LauncherApps la = getSystemService(LauncherApps.class);
			if (um != null && la != null) for (final UserHandle profile : (profiles = um.getUserProfiles())) {
				if (profile.equals(Process.myUserHandle())) continue;
				if (getApplicationInfo(la, WECHAT_PACKAGE, profile) == null) continue;
				if (getApplicationInfo(la, ANDROID_AUTO_PACKAGE, profile) == null)
					android_auto_unavailable_in_profiles.add(profile.hashCode());
			}
		}
		preference_extension.setEnabled(wechat_installed);
		preference_extension.setSelectable(! android_auto_available || ! android_auto_unavailable_in_profiles.isEmpty());
		preference_extension.setSummary(! android_auto_available ? getText(R.string.pref_extension_summary)
				: android_auto_unavailable_in_profiles.isEmpty() ? getText(R.string.pref_extension_summary_installed)
				: getString(R.string.pref_extension_summary_not_cloned_in_island,
				profiles.size() <= 2/* Just one Island space */? "" : android_auto_unavailable_in_profiles.toString()));
		preference_extension.setOnPreferenceClickListener(! android_auto_available ? this::installExtension
                : ! android_auto_unavailable_in_profiles.isEmpty() ? this::showExtensionInIsland : null);

		final Preference preference_agent = findPreference(getString(R.string.pref_agent));
		final int agent_version = getPackageVersion(AGENT_WECHAT_PACKAGE);
		preference_agent.setEnabled(wechat_installed);
		if (agent_version >= CURRENT_AGENT_VERSION) {
			final Intent launcher_intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER).setPackage(AGENT_WECHAT_PACKAGE);
			final boolean disabled = pm.queryIntentActivities(launcher_intent, 0).isEmpty();
			final @StringRes int prefix = (disabled ? R.string.pref_agent_summary_prefix_disabled : R.string.pref_agent_summary_prefix_enabled);
			preference_agent.setSummary(getString(prefix) + "\n" + getString(R.string.pref_agent_summary_installed));
			preference_agent.setOnPreferenceClickListener(pref -> selectAgentLabel());
		} else {
			preference_agent.setSummary(agent_version < 0 ? R.string.pref_agent_summary : R.string.pref_agent_summary_update);
			preference_agent.setOnPreferenceClickListener(pref -> installAssetApk("agent.apk"));
		}

		final boolean standalone = isStandalone();
		final TwoStatePreference preference_hide = (TwoStatePreference) findPreference(getString(R.string.pref_hide));
		if (preference_hide != null) {
			if (standalone) {
				final ComponentName component = new ComponentName(this, getClass());
				final int state = pm.getComponentEnabledSetting(component);
				preference_hide.setChecked(state == COMPONENT_ENABLED_STATE_DISABLED);
				preference_hide.setOnPreferenceChangeListener(this::toggleHidingLauncherIcon);
			} else getPreferenceScreen().removePreference(preference_hide);
		}

		final Preference pref_ver = findPreference(getString(R.string.pref_version));
		if (pref_ver != null) {
			if (! standalone) getPreferenceScreen().removePreference(pref_ver);
			else try { pref_ver.setSummary(pm.getPackageInfo(getPackageName(), 0).versionName); } catch (final NameNotFoundException ignored) {}
		}
	}

	private boolean selectAgentLabel() {
		final PackageManager pm = getPackageManager();
		final Intent query = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER).setPackage(AGENT_WECHAT_PACKAGE);
		final List<ResolveInfo> resolves = pm.queryIntentActivities(query, PackageManager.GET_DISABLED_COMPONENTS);
		final int size = resolves.size();
		if (size <= 1) throw new IllegalStateException("No activities found for " + query);
		final CharSequence[] labels = new CharSequence[size + 1];
		final String[] names = new String[size];
		for (int i = 0; i < size; i ++) {
			final ActivityInfo activity = resolves.get(i).activityInfo;
			labels[i] = activity.loadLabel(pm);
			names[i] = activity.name;
		}
		labels[size] = getText(R.string.action_disable_agent_launcher_entrance);
		new AlertDialog.Builder(this).setSingleChoiceItems(labels, -1, (dialog, which) -> {	// TODO: Item cannot be selected on Sony device?
			for (int i = 0; i < names.length; i ++)
				pm.setComponentEnabledSetting(new ComponentName(AGENT_WECHAT_PACKAGE, names[i]),
						i == which ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP);
			dialog.dismiss();
		}).show();
		return true;
	}

	private boolean toggleHidingLauncherIcon(@SuppressWarnings("unused") final Preference unused, final Object value) {
		final boolean start_from_launcher = getIntent().getAction() != null;
		if (start_from_launcher && value == Boolean.TRUE) {
			new AlertDialog.Builder(this).setMessage(R.string.prompt_hide_prerequisite).setPositiveButton(android.R.string.cancel, null).show();
			return false;
		}
		getPackageManager().setComponentEnabledSetting(new ComponentName(this, getClass()),
				value != Boolean.TRUE ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP);
		return true;
	}

	private boolean isStandalone() {
		return getPackageName().equals(BuildConfig.APPLICATION_ID);
	}

	private boolean isDecoratorRunning() {
		final Intent service = new Intent(this, WeChatDecorator.class).setAction(NevoDecoratorService.ACTION_DECORATOR_SERVICE);
		return mDummyReceiver.peekService(this, service) != null;
	}

	private boolean installExtension(@SuppressWarnings("unused") final Preference unused) {
		if (isPlayStoreSystemApp()) {
			new AlertDialog.Builder(this).setMessage(R.string.prompt_extension_install)
					.setPositiveButton(R.string.action_install_android_auto, (d, c) -> showAndroidAutoInPlayStore())
					.setNeutralButton(R.string.action_install_dummy_auto, (d, c) -> installDummyAuto()).show();
		} else installDummyAuto();
		return true;
	}

	@SuppressLint("InlinedApi") private boolean showExtensionInIsland(@SuppressWarnings("unused") final Preference unused) {
	    try {
            startActivity(new Intent(Intent.ACTION_SHOW_APP_INFO).putExtra(Intent.EXTRA_PACKAGE_NAME, ANDROID_AUTO_PACKAGE).setPackage(ISLAND_PACKAGE));
        } catch (final Exception ignored) {}
	    return true;
    }

	private void showAndroidAutoInPlayStore() {
		try {
			startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + ANDROID_AUTO_PACKAGE))
					.setPackage(PLAY_STORE_PACKAGE).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
		} catch(final ActivityNotFoundException e) { /* In case of Google Play malfunction */ }
	}

	private void installDummyAuto() {
		installAssetApk("dummy-auto.apk");
	}

	private boolean installAssetApk(final String asset_name) {
		try {
			final String authority = getPackageManager().getProviderInfo(new ComponentName(this, AssetFileProvider.class), 0).authority;
			startActivity(new Intent(Intent.ACTION_INSTALL_PACKAGE, Uri.parse("content://" + authority + "/" + asset_name)).addFlags(FLAG_GRANT_READ_URI_PERMISSION));
		} catch (final NameNotFoundException | ActivityNotFoundException ignored) {}	// Should never happen
		return true;
	}

	private int getPackageVersion(final String pkg) {
		try {
			return getPackageManager().getPackageInfo(pkg, 0).versionCode;
		} catch (final NameNotFoundException e) {
			return -1;
		}
	}

	@RequiresApi(N) @SuppressLint("NewApi")
	private static ApplicationInfo getApplicationInfo(final LauncherApps la, final String pkg, final UserHandle profile) {
		try {
			return la.getApplicationInfo(pkg, 0, profile);
		} catch (final NameNotFoundException e) { return null; }
	}

	@Override protected void onDestroy() {
		getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
		super.onDestroy();
	}

	private boolean installNevolution(final @SuppressWarnings("unused") Preference preference) {
		try {
			startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(APP_MARKET_PREFIX + NEVOLUTION_PACKAGE)));
		} catch (final ActivityNotFoundException ignored) {}	// TODO: Landing web page
		return true;
	}

	private boolean activate(final @SuppressWarnings("unused") Preference preference) {
		try {
			startActivityForResult(new Intent("com.oasisfeng.nevo.action.ACTIVATE_DECORATOR").setPackage(NEVOLUTION_PACKAGE)
					.putExtra("nevo.decorator", new ComponentName(this, WeChatDecorator.class))
					.putExtra("nevo.target", WECHAT_PACKAGE), 0);
		} catch (final ActivityNotFoundException e) {
			startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER).setPackage(NEVOLUTION_PACKAGE));
		}
		return true;
	}

	private boolean isPlayStoreSystemApp() {
		try {
			return (getPackageManager().getApplicationInfo(PLAY_STORE_PACKAGE, 0).flags & ApplicationInfo.FLAG_SYSTEM) != 0;
		} catch (final NameNotFoundException e) {
			return false;
		}
	}

	private final SharedPreferences.OnSharedPreferenceChangeListener mPreferencesChangeListener = (prefs, key) -> {
		Log.d(TAG, "Settings changed, notify decorator now.");
		sendBroadcast(new Intent(WeChatDecorator.ACTION_SETTINGS_CHANGED).setPackage(getPackageName()).putExtra(key, prefs.getBoolean(key, false)));
	};

	private final BroadcastReceiver mDummyReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context c, final Intent i) {}};
}