package com.miraclegarden.smsmessage.service;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import android.util.Log;

import com.miraclegarden.smsmessage.App;
import com.miraclegarden.smsmessage.KeepAliveSettings;
import com.miraclegarden.smsmessage.Activity.NotificationActivity;
import com.miraclegarden.smsmessage.MessageInfo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 唤醒监听列表中的 App，使其进程启动、Xposed Hook 重新加载。
 * Root 设备：monkey 轻量启动 + 可选返回桌面 + 电池白名单。
 */
public final class MonitoredAppActivator {

    private static final String TAG = "MonitoredAppActivator";
    private static final String PREF = "keep_alive";
    private static final String KEY_LAST_WAKE_PREFIX = "last_wake_";

    private MonitoredAppActivator() {
    }

    public static void activateAllAsync(Context context) {
        if (!KeepAliveSettings.isEnabled(context)) {
            return;
        }
        Context appContext = context.getApplicationContext();
        new Thread(() -> activateAll(appContext), "MonitoredAppActivator").start();
    }

    public static void activateAll(Context context) {
        if (!KeepAliveSettings.isEnabled(context)) {
            return;
        }
        if (!NotificationService.isMonitoringActive(context)) {
            Log.d(TAG, "skip activate: monitoring off");
            return;
        }

        List<MessageInfo> apps = App.getNotiList(context);
        if (apps.isEmpty()) {
            return;
        }

        Log.i(TAG, "activating " + apps.size() + " monitored app(s)");
        NotificationActivity.sendMessage("正在唤醒监听 App（" + apps.size() + " 个）...");

        int ok = 0;
        for (MessageInfo info : apps) {
            if (info == null || TextUtils.isEmpty(info.getPackageName())) {
                continue;
            }
            if (context.getPackageName().equals(info.getPackageName())) {
                continue;
            }
            if (activateOne(context, info)) {
                ok++;
            }
        }

        NotificationService.toggleNotificationListenerService(context);
        NotificationActivity.sendMessage("App 保活完成: " + ok + "/" + apps.size());
    }

    private static boolean activateOne(Context context, MessageInfo info) {
        String pkg = info.getPackageName();
        String label = !TextUtils.isEmpty(info.getAppName()) ? info.getAppName() : pkg;

        if (isInCooldown(context, pkg)) {
            Log.d(TAG, "skip cooldown: " + pkg);
            NotificationActivity.sendMessage("[保活] " + label + " 冷却中，稍后重试");
            return false;
        }

        applyBatteryWhitelist(pkg);
        boolean wasAlive = isProcessAlive(context, pkg);

        if (wasAlive && KeepAliveSettings.isStealthMode(context)) {
            if (!isProcessCached(context, pkg)) {
                Log.d(TAG, "stealth skip (active): " + pkg);
                return true;
            }
            Log.i(TAG, "stealth headless wake (cached): " + pkg);
            if (wakeHeadlessByRoot(pkg)) {
                markWake(context, pkg);
                NotificationActivity.sendMessage("[保活] " + label + " 已唤醒后台进程（无界面）");
                return true;
            }
        }

        if (KeepAliveSettings.killBeforeLaunch(context) && KeepAliveSettings.preferRoot(context)) {
            forceStopByRoot(pkg);
            sleepQuietly(800);
            wasAlive = false;
        }

        boolean success = false;
        if (KeepAliveSettings.preferRoot(context)) {
            success = wakeByRoot(context, pkg);
        }
        if (!success) {
            success = wakeByLaunchIntent(context, pkg);
        }

        if (success) {
            markWake(context, pkg);
            if (KeepAliveSettings.returnHome(context) && KeepAliveSettings.preferRoot(context)) {
                long homeDelay = KeepAliveSettings.isStealthMode(context) ? 400L : 1500L;
                sleepQuietly(homeDelay);
                pressHomeByRoot();
            }
            NotificationActivity.sendMessage("[保活] " + label + " 已启动");
            Log.i(TAG, "woke " + pkg);
        } else {
            NotificationActivity.sendMessage("[保活] " + label + " 唤起失败（检查 Root / Magisk 授权）");
            Log.w(TAG, "wake failed " + pkg);
        }
        return success;
    }

    private static void forceStopByRoot(String packageName) {
        try {
            Runtime.getRuntime().exec(new String[]{
                    "su", "-c", "am force-stop " + packageName
            }).waitFor();
        } catch (Throwable t) {
            Log.w(TAG, "force-stop failed " + packageName + ": " + t.getMessage());
        }
    }

    private static boolean isInCooldown(Context context, String packageName) {
        long last = context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
                .getLong(KEY_LAST_WAKE_PREFIX + packageName, 0L);
        long cooldownMs = TimeUnit.MINUTES.toMillis(KeepAliveSettings.getCooldownMinutes(context));
        return System.currentTimeMillis() - last < cooldownMs;
    }

    private static void markWake(Context context, String packageName) {
        context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
                .edit()
                .putLong(KEY_LAST_WAKE_PREFIX + packageName, System.currentTimeMillis())
                .apply();
    }

    private static boolean isProcessAlive(Context context, String packageName) {
        if (isProcessAliveByRoot(packageName)) {
            return true;
        }
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if (am == null) {
            return false;
        }
        List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
        if (processes == null) {
            return false;
        }
        for (ActivityManager.RunningAppProcessInfo info : processes) {
            if (packageName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }

    /** 进程在但已被系统冻结（cached），此时 TG 可能不处理推送。 */
    private static boolean isProcessCached(Context context, String packageName) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if (am == null) {
            return false;
        }
        List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
        if (processes == null) {
            return false;
        }
        for (ActivityManager.RunningAppProcessInfo info : processes) {
            if (!packageName.equals(info.processName)) {
                continue;
            }
            return info.importance >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
        }
        return false;
    }

    /** 无界面唤醒 TG 前台 Service，让后台继续收推送。 */
    private static boolean wakeHeadlessByRoot(String packageName) {
        if (!packageName.contains("telegram")) {
            return false;
        }
        String component = packageName + "/org.telegram.messenger.NotificationsService";
        try {
            Process process = Runtime.getRuntime().exec(new String[]{
                    "su", "-c", "am start-foreground-service -n " + component
            });
            if (process.waitFor() == 0) {
                return true;
            }
        } catch (Throwable t) {
            Log.w(TAG, "headless fgs wake failed " + packageName + ": " + t.getMessage());
        }
        try {
            Process process = Runtime.getRuntime().exec(new String[]{
                    "su", "-c", "am startservice -n " + component
            });
            return process.waitFor() == 0;
        } catch (Throwable t) {
            Log.w(TAG, "headless service wake failed " + packageName + ": " + t.getMessage());
            return false;
        }
    }

    private static boolean isProcessAliveByRoot(String packageName) {
        try {
            Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", "pidof " + packageName});
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line = reader.readLine();
                return process.waitFor() == 0 && line != null && !line.trim().isEmpty();
            }
        } catch (Throwable t) {
            return false;
        }
    }

    private static boolean wakeByRoot(Context context, String packageName) {
        String component = resolveLauncherComponent(context, packageName);
        if (!TextUtils.isEmpty(component)) {
            try {
                Process process = Runtime.getRuntime().exec(new String[]{
                        "su", "-c",
                        "am start -n " + component
                                + " -a android.intent.action.MAIN"
                                + " -c android.intent.category.LAUNCHER"
                                + " --activity-brought-to-front"
                                + " --activity-no-animation"
                });
                if (process.waitFor() == 0) {
                    return true;
                }
            } catch (Throwable t) {
                Log.w(TAG, "am start failed " + packageName + ": " + t.getMessage());
            }
        }
        try {
            Process process = Runtime.getRuntime().exec(new String[]{
                    "su", "-c",
                    "monkey -p " + packageName + " -c android.intent.category.LAUNCHER 1"
            });
            return process.waitFor() == 0;
        } catch (Throwable t) {
            Log.w(TAG, "monkey wake failed " + packageName + ": " + t.getMessage());
            return false;
        }
    }

    private static String resolveLauncherComponent(Context context, String packageName) {
        try {
            PackageManager pm = context.getPackageManager();
            Intent intent = pm.getLaunchIntentForPackage(packageName);
            if (intent != null && intent.getComponent() != null) {
                return intent.getComponent().flattenToShortString();
            }
            Intent query = new Intent(Intent.ACTION_MAIN);
            query.addCategory(Intent.CATEGORY_LAUNCHER);
            query.setPackage(packageName);
            List<ResolveInfo> list = pm.queryIntentActivities(query, 0);
            if (!list.isEmpty()) {
                return list.get(0).activityInfo.packageName + "/"
                        + list.get(0).activityInfo.name;
            }
        } catch (Throwable ignored) {
        }
        return null;
    }

    private static boolean wakeByLaunchIntent(Context context, String packageName) {
        try {
            PackageManager pm = context.getPackageManager();
            Intent intent = pm.getLaunchIntentForPackage(packageName);
            if (intent == null) {
                Intent query = new Intent(Intent.ACTION_MAIN);
                query.addCategory(Intent.CATEGORY_LAUNCHER);
                query.setPackage(packageName);
                List<ResolveInfo> list = pm.queryIntentActivities(query, 0);
                if (list.isEmpty()) {
                    return false;
                }
                intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                intent.setClassName(list.get(0).activityInfo.packageName, list.get(0).activityInfo.name);
            }
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_CLEAR_TOP
                    | Intent.FLAG_ACTIVITY_NO_ANIMATION);
            context.startActivity(intent);
            return true;
        } catch (Throwable t) {
            Log.w(TAG, "launch wake failed " + packageName + ": " + t.getMessage());
            return false;
        }
    }

    private static void applyBatteryWhitelist(String packageName) {
        try {
            Runtime.getRuntime().exec(new String[]{
                    "su", "-c", "dumpsys deviceidle whitelist +" + packageName
            }).waitFor();
        } catch (Throwable ignored) {
        }
    }

    private static void pressHomeByRoot() {
        try {
            Runtime.getRuntime().exec(new String[]{"su", "-c", "input keyevent 3"}).waitFor();
        } catch (Throwable ignored) {
        }
    }

    private static void sleepQuietly(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
