package com.yuanxuan.webshell.core.web_shell_core;

import android.app.ActivityManager;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.SystemClock;
import android.webkit.CookieManager;
import android.webkit.WebStorage;
import android.webkit.WebView;

import androidx.annotation.NonNull;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;

public class CoreShellActivity extends FlutterActivity {
    private static final String DEVICE_CHANNEL = "app_shell/device";
    private static final String DEBUG_PROCESS_PREFS = "app_shell_debug_process";
    private static final String DEBUG_PROCESS_PID_KEY = "pid";
    private String webViewDataDirectorySuffix;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        terminatePreviousDebugProcessIfNeeded();
        prepareWebViewDataDirectory();
        super.onCreate(savedInstanceState);
        registerCurrentDebugProcess();
    }

    @Override
    protected void onDestroy() {
        clearCurrentDebugProcessRegistration();
        super.onDestroy();
    }

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        new MethodChannel(
                flutterEngine.getDartExecutor().getBinaryMessenger(),
                DEVICE_CHANNEL
        ).setMethodCallHandler((call, result) -> {
            switch (call.method) {
                case "getAndroidWebViewInfo":
                    result.success(buildAndroidWebViewInfo());
                    break;
                case "resetAndroidWebViewState":
                    resetAndroidWebViewState(result);
                    break;
                default:
                    result.notImplemented();
                    break;
            }
        });
    }

    private Map<String, Object> buildAndroidWebViewInfo() {
        final Map<String, Object> info = new HashMap<>();
        info.put("sdkInt", Build.VERSION.SDK_INT);
        info.put("manufacturer", Build.MANUFACTURER);
        info.put("brand", Build.BRAND);
        info.put("model", Build.MODEL);
        if (webViewDataDirectorySuffix != null) {
            info.put("webViewDataDirectorySuffix", webViewDataDirectorySuffix);
        }

        final PackageInfo currentWebViewPackage = getCurrentWebViewPackageCompat();
        if (currentWebViewPackage != null) {
            info.put("webViewPackageName", currentWebViewPackage.packageName);
            if (currentWebViewPackage.versionName != null) {
                info.put("webViewVersionName", currentWebViewPackage.versionName);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                info.put(
                        "webViewLongVersionCode",
                        currentWebViewPackage.getLongVersionCode()
                );
            } else {
                info.put(
                        "webViewLongVersionCode",
                        (long) currentWebViewPackage.versionCode
                );
            }
        }
        return info;
    }

    private void prepareWebViewDataDirectory() {
        webViewDataDirectorySuffix = null;
        if (!isDebuggableBuild() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return;
        }

        clearLegacyDebugWebViewData();
    }

    private void terminatePreviousDebugProcessIfNeeded() {
        if (!isDebuggableBuild()) {
            return;
        }

        final SharedPreferences preferences = getSharedPreferences(
                DEBUG_PROCESS_PREFS,
                MODE_PRIVATE
        );
        final int currentPid = Process.myPid();
        final int previousPid = preferences.getInt(DEBUG_PROCESS_PID_KEY, -1);
        if (previousPid <= 0 || previousPid == currentPid) {
            return;
        }

        if (!isSamePackageProcessRunning(previousPid)) {
            preferences.edit().remove(DEBUG_PROCESS_PID_KEY).apply();
            return;
        }

        try {
            Process.killProcess(previousPid);
            SystemClock.sleep(180);
        } catch (RuntimeException ignored) {
            // 忽略终止旧进程失败的情况，并继续使用当前进程启动。
        }
    }

    private void registerCurrentDebugProcess() {
        if (!isDebuggableBuild()) {
            return;
        }

        getSharedPreferences(DEBUG_PROCESS_PREFS, MODE_PRIVATE)
                .edit()
                .putInt(DEBUG_PROCESS_PID_KEY, Process.myPid())
                .apply();
    }

    private void clearCurrentDebugProcessRegistration() {
        if (!isDebuggableBuild()) {
            return;
        }

        final SharedPreferences preferences = getSharedPreferences(
                DEBUG_PROCESS_PREFS,
                MODE_PRIVATE
        );
        if (preferences.getInt(DEBUG_PROCESS_PID_KEY, -1) != Process.myPid()) {
            return;
        }
        preferences.edit().remove(DEBUG_PROCESS_PID_KEY).apply();
    }

    private boolean isSamePackageProcessRunning(int pid) {
        final ActivityManager activityManager =
                (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        if (activityManager == null) {
            return false;
        }

        for (final ActivityManager.RunningAppProcessInfo processInfo
                : activityManager.getRunningAppProcesses()) {
            if (processInfo.pid == pid) {
                return getPackageName().equals(processInfo.processName);
            }
        }
        return false;
    }

    private void clearLegacyDebugWebViewData() {
        try {
            final File appWebViewDir = new File(getApplicationInfo().dataDir, "app_webview");
            deleteRecursively(appWebViewDir);
            deleteDatabase("webview.db");
            deleteDatabase("webviewCache.db");
        } catch (RuntimeException ignored) {
            // 忽略旧设备上的清理失败，继续执行启动流程。
        }
    }

    private boolean isDebuggableBuild() {
        return (getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    }

    private void deleteRecursively(File target) {
        if (target == null || !target.exists()) {
            return;
        }

        if (target.isDirectory()) {
            final File[] children = target.listFiles();
            if (children != null) {
                for (final File child : children) {
                    deleteRecursively(child);
                }
            }
        }


        target.delete();
    }

    private PackageInfo getCurrentWebViewPackageCompat() {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                return WebView.getCurrentWebViewPackage();
            }
        } catch (RuntimeException ignored) {
            return null;
        }
        return null;
    }

    private void resetAndroidWebViewState(@NonNull MethodChannel.Result result) {
        try {
            WebStorage.getInstance().deleteAllData();

            final CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.removeSessionCookies(null);
            cookieManager.removeAllCookies(value -> {
                try {
                    cookieManager.flush();
                    WebView.clearClientCertPreferences(() -> result.success(true));
                } catch (RuntimeException error) {
                    result.error(
                            "webview_reset_failed",
                            error.toString(),
                            null
                    );
                }
            });
        } catch (RuntimeException error) {
            result.error("webview_reset_failed", error.toString(), null);
        }
    }
}
