package com.okithaki.autoapp;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;

import androidx.webkit.ProxyConfig;
import androidx.webkit.ProxyController;
import androidx.webkit.WebViewFeature;

import com.google.firebase.messaging.FirebaseMessaging;

import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * OK ITHAKI V249435 real Tor-safe WebView transport.
 *
 * The implementation uses an already-installed/running Orbot SOCKS endpoint on
 * 127.0.0.1:9050 and AndroidX WebKit ProxyController. There is deliberately no
 * direct fallback rule: when the proxy is unavailable, WebView requests fail
 * instead of silently exposing the direct IP. Calls/WebRTC, FCM and local LAN
 * Mesh are disabled by the application while Tor Safe Mode is requested.
 */
public final class TorIntegrationV249435 {
    private static final String PREFS = "ok_ithaki_prefs";
    private static final String KEY_REQUESTED = "tor_safe_requested_v249435";
    private static final String KEY_APPLIED = "tor_proxy_applied_v249435";
    private static final String KEY_VERIFIED = "tor_verified_v249435";
    private static final String KEY_LAST_ERROR = "tor_last_error_v249435";
    private static final String ORBOT_PACKAGE = "org.torproject.android";
    private static final String SOCKS_PROXY = "socks://127.0.0.1:9050";


    // V249469: process-lifetime proxy callback executor.
    // Android WebView may deliver a proxy callback after the initiating method returns,
    // therefore this executor must never be shutdown while the process is alive.
    private static final ExecutorService PROXY_CALLBACK_EXECUTOR =
            Executors.newSingleThreadExecutor();
    private TorIntegrationV249435() { }

    public static boolean isRequested(Context context) {
        try { return context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getBoolean(KEY_REQUESTED, false); }
        catch (Exception ignored) { return false; }
    }

    private static boolean packageInstalled(Context context, String name) {
        try { context.getPackageManager().getPackageInfo(name, 0); return true; }
        catch (PackageManager.NameNotFoundException e) { return false; }
        catch (Exception e) { return false; }
    }

    private static boolean portOpen(int port, int timeoutMs) {
        Socket socket = new Socket();
        try {
            socket.connect(new InetSocketAddress("127.0.0.1", port), timeoutMs);
            return true;
        } catch (Exception ignored) {
            return false;
        } finally {
            try { socket.close(); } catch (Exception ignored) { }
        }
    }

    private static SharedPreferences prefs(Context context) {
        return context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
    }

    private static void suppressFcmForTor(Context context) {
        try { FirebaseMessaging.getInstance().setAutoInitEnabled(false); } catch (Exception ignored) { }
        try { FirebaseMessaging.getInstance().deleteToken(); } catch (Exception ignored) { }
        try {
            prefs(context).edit()
                    .putString("ok_fcm_token", "")
                    .putBoolean("tor_fcm_suppressed_v249435", true)
                    .apply();
        } catch (Exception ignored) { }
    }

    private static void restoreFcmAfterTor(Context context) {
        try { FirebaseMessaging.getInstance().setAutoInitEnabled(true); } catch (Exception ignored) { }
        try { prefs(context).edit().putBoolean("tor_fcm_suppressed_v249435", false).apply(); }
        catch (Exception ignored) { }
    }

    private static boolean verifyThroughSocks() {
        HttpURLConnection connection = null;
        try {
            Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 9050));
            connection = (HttpURLConnection) new URL("https://check.torproject.org/api/ip").openConnection(proxy);
            connection.setConnectTimeout(12000);
            connection.setReadTimeout(12000);
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("User-Agent", "OK-ITHAKI-V249435-Tor-Check");
            int code = connection.getResponseCode();
            if (code < 200 || code >= 300) return false;
            InputStream in = connection.getInputStream();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[2048];
            int n;
            while ((n = in.read(buffer)) > 0 && out.size() < 64_000) out.write(buffer, 0, n);
            in.close();
            JSONObject json = new JSONObject(new String(out.toByteArray(), StandardCharsets.UTF_8));
            return json.optBoolean("IsTor", false);
        } catch (Exception ignored) {
            return false;
        } finally {
            try { if (connection != null) connection.disconnect(); } catch (Exception ignored) { }
        }
    }

    public static JSONObject openOrbot(Context context) {
        JSONObject out = status(context);
        try {
            Intent launch = context.getPackageManager().getLaunchIntentForPackage(ORBOT_PACKAGE);
            if (launch != null) {
                launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(launch);
                out.put("opened", true);
                out.put("reason", "orbot_opened");
                return out;
            }
            Intent store = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + ORBOT_PACKAGE));
            store.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(store);
            out.put("opened", true);
            out.put("reason", "orbot_store_opened");
        } catch (Exception first) {
            try {
                Intent web = new Intent(Intent.ACTION_VIEW, Uri.parse("https://guardianproject.info/apps/org.torproject.android/"));
                web.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(web);
                out.put("opened", true);
                out.put("reason", "orbot_download_page_opened");
            } catch (Exception ignored) {
                try { out.put("opened", false); out.put("reason", "orbot_open_failed"); } catch (Exception ignored2) { }
            }
        }
        return out;
    }

    public static JSONObject enableBlocking(Context context) {
        JSONObject out = new JSONObject();
        try {
            SharedPreferences sp = prefs(context);
            sp.edit().putBoolean(KEY_REQUESTED, true).putBoolean(KEY_APPLIED, false).putBoolean(KEY_VERIFIED, false).apply();
            suppressFcmForTor(context);

            boolean installed = packageInstalled(context, ORBOT_PACKAGE);
            boolean socksOpen = portOpen(9050, 650);
            boolean proxyFeature = WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE);
            out.put("ok", false);
            out.put("version", "V249435-real-tor-safe-webview");
            out.put("external_orbot_detected", installed);
            out.put("orbot_socks_open", socksOpen);
            out.put("webview_proxy_override_supported", proxyFeature);
            if (!installed) {
                sp.edit().putString(KEY_LAST_ERROR, "orbot_not_installed").apply();
                out.put("reason", "orbot_not_installed");
                return out;
            }
            if (!socksOpen) {
                sp.edit().putString(KEY_LAST_ERROR, "orbot_not_running_or_not_bootstrapped").apply();
                out.put("reason", "orbot_not_running_or_not_bootstrapped");
                return out;
            }
            if (!proxyFeature) {
                sp.edit().putString(KEY_LAST_ERROR, "webview_proxy_override_unsupported").apply();
                out.put("reason", "webview_proxy_override_unsupported");
                return out;
            }

            ProxyConfig config = new ProxyConfig.Builder()
                    .addProxyRule(SOCKS_PROXY, ProxyConfig.MATCH_ALL_SCHEMES)
                    .removeImplicitRules()
                    .build();
            CountDownLatch latch = new CountDownLatch(1);
            ProxyController.getInstance().setProxyOverride(config, PROXY_CALLBACK_EXECUTOR, latch::countDown);
            boolean applied = latch.await(5, TimeUnit.SECONDS);
            if (!applied) {
                sp.edit().putString(KEY_LAST_ERROR, "proxy_apply_timeout").apply();
                out.put("reason", "proxy_apply_timeout");
                return out;
            }

            boolean verified = verifyThroughSocks();
            sp.edit()
                    .putBoolean(KEY_APPLIED, true)
                    .putBoolean(KEY_VERIFIED, verified)
                    .putString(KEY_LAST_ERROR, verified ? "" : "tor_check_not_verified")
                    .apply();
            out.put("ok", true);
            out.put("native_proxy_active", true);
            out.put("tor_verified", verified);
            out.put("webview_network_requests_proxy", true);
            out.put("direct_fallback", false);
            out.put("webrtc_calls_blocked", true);
            out.put("fcm_suppressed", true);
            out.put("local_mesh_suppressed", true);
            out.put("reason", verified ? "tor_active_verified" : "tor_active_unverified_check");
            return out;
        } catch (Exception exc) {
            try {
                prefs(context).edit().putBoolean(KEY_APPLIED, false).putString(KEY_LAST_ERROR, String.valueOf(exc.getMessage())).apply();
                out.put("ok", false);
                out.put("reason", "tor_enable_error");
                out.put("error", String.valueOf(exc.getMessage()));
            } catch (Exception ignored) { }
            return out;
        }
    }

    public static JSONObject disableBlocking(Context context) {
        JSONObject out = new JSONObject();
        try {
            boolean supported = WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE);
            if (supported) {
                CountDownLatch latch = new CountDownLatch(1);
                ProxyController.getInstance().clearProxyOverride(PROXY_CALLBACK_EXECUTOR, latch::countDown);
                latch.await(5, TimeUnit.SECONDS);
            }
            prefs(context).edit()
                    .putBoolean(KEY_REQUESTED, false)
                    .putBoolean(KEY_APPLIED, false)
                    .putBoolean(KEY_VERIFIED, false)
                    .putString(KEY_LAST_ERROR, "")
                    .apply();
            restoreFcmAfterTor(context);
            out.put("ok", true);
            out.put("version", "V249435-real-tor-safe-webview");
            out.put("native_proxy_active", false);
            out.put("reason", "tor_disabled");
        } catch (Exception exc) {
            try { out.put("ok", false); out.put("reason", "tor_disable_error"); out.put("error", String.valueOf(exc.getMessage())); }
            catch (Exception ignored) { }
        }
        return out;
    }

    public static JSONObject applySavedModeBlocking(Context context) {
        if (!isRequested(context)) return status(context);
        return enableBlocking(context);
    }

    public static JSONObject status(Context context) {
        JSONObject out = new JSONObject();
        try {
            SharedPreferences sp = prefs(context);
            boolean requested = sp.getBoolean(KEY_REQUESTED, false);
            boolean applied = sp.getBoolean(KEY_APPLIED, false);
            boolean verified = sp.getBoolean(KEY_VERIFIED, false);
            boolean installed = packageInstalled(context, ORBOT_PACKAGE);
            boolean socks = portOpen(9050, 300);
            boolean proxyFeature = WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE);
            out.put("ok", true);
            out.put("version", "V249435-real-tor-safe-webview");
            out.put("tor_safe_requested", requested);
            out.put("native_proxy_active", requested && applied && socks && proxyFeature);
            out.put("tor_verified", requested && verified);
            out.put("external_orbot_detected", installed);
            out.put("orbot_socks_open", socks);
            out.put("webview_proxy_override_supported", proxyFeature);
            out.put("webview_network_requests_proxy", requested && applied);
            out.put("direct_fallback", false);
            out.put("webrtc_calls_blocked", requested);
            out.put("fcm_suppressed", requested);
            out.put("local_mesh_suppressed", requested);
            out.put("last_error", sp.getString(KEY_LAST_ERROR, ""));
            out.put("disclosure", "Tor Safe Mode routes WebView network requests through Orbot without a configured direct fallback. WebRTC calls, FCM and local Mesh are disabled while active.");
        } catch (Exception exc) {
            try { out.put("ok", false); out.put("native_proxy_active", false); out.put("error", String.valueOf(exc.getMessage())); }
            catch (Exception ignored) { }
        }
        return out;
    }
}
