package com.miraclegarden.smsmessage.mmp;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.miraclegarden.smsmessage.AppConfig;

import org.json.JSONObject;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 领取台设置：本地 SharedPreferences 优先，能连上调试台时再同步 Hook 侧参数。
 */
public final class MmpSettingsClient {

    private static final String TAG = "MmpSettingsClient";
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectTimeout(4, TimeUnit.SECONDS)
            .readTimeout(4, TimeUnit.SECONDS)
            .writeTimeout(4, TimeUnit.SECONDS)
            .build();
    private static final ExecutorService EXEC = Executors.newSingleThreadExecutor();
    private static final Handler MAIN = new Handler(Looper.getMainLooper());

    public interface CallbackJson {
        void onResult(JSONObject json, String error);
    }

    private MmpSettingsClient() {
    }

    /** 先本地，再尝试合并调试台（Hook 冷却等） */
    public static void load(Context context, CallbackJson cb) {
        final Context app = context != null ? context.getApplicationContext() : null;
        EXEC.execute(() -> {
            JSONObject local = MmpLocalSettings.load(app);
            Exception last = null;
            for (String base : AppConfig.DEBUG_SERVER_URLS) {
                if (base == null || base.isEmpty()) {
                    continue;
                }
                try {
                    Request req = new Request.Builder()
                            .url(base.replaceAll("/$", "") + "/api/mmp/settings")
                            .get()
                            .build();
                    try (Response resp = CLIENT.newCall(req).execute()) {
                        if (resp.isSuccessful() && resp.body() != null) {
                            JSONObject remote = new JSONObject(resp.body().string());
                            // 远程覆盖 Hook 相关；手机专属开关保留本地
                            boolean launch = local.optBoolean("autoLaunchTngIfKilled", true);
                            boolean watch = local.optBoolean("autoWatchWhileOpen", true);
                            MmpLocalSettings.mergeInto(local, remote);
                            local.put("autoLaunchTngIfKilled", launch);
                            local.put("autoWatchWhileOpen", watch);
                            MmpLocalSettings.save(app, local);
                            JSONObject out = local;
                            MAIN.post(() -> cb.onResult(out, null));
                            return;
                        }
                    }
                } catch (Exception e) {
                    last = e;
                }
            }
            JSONObject out = local;
            String tip = last != null
                    ? ("已用本地设置（调试台未连上：" + last.getMessage() + "）")
                    : null;
            MAIN.post(() -> cb.onResult(out, tip));
        });
    }

    /** 始终写本地；能连调试台则同步 Hook 参数 */
    public static void save(Context context, JSONObject body, CallbackJson cb) {
        final Context app = context != null ? context.getApplicationContext() : null;
        EXEC.execute(() -> {
            MmpLocalSettings.save(app, body);
            JSONObject saved = MmpLocalSettings.load(app);
            Exception last = null;
            boolean remoteOk = false;
            for (String base : AppConfig.DEBUG_SERVER_URLS) {
                if (base == null || base.isEmpty()) {
                    continue;
                }
                try {
                    Request req = new Request.Builder()
                            .url(base.replaceAll("/$", "") + "/api/mmp/settings")
                            .post(RequestBody.create(saved.toString(), JSON))
                            .build();
                    try (Response resp = CLIENT.newCall(req).execute()) {
                        if (resp.isSuccessful() && resp.body() != null) {
                            JSONObject remote = new JSONObject(resp.body().string());
                            boolean launch = saved.optBoolean("autoLaunchTngIfKilled", true);
                            boolean watch = saved.optBoolean("autoWatchWhileOpen", true);
                            MmpLocalSettings.mergeInto(saved, remote);
                            saved.put("autoLaunchTngIfKilled", launch);
                            saved.put("autoWatchWhileOpen", watch);
                            MmpLocalSettings.save(app, saved);
                            remoteOk = true;
                            break;
                        }
                    }
                } catch (Exception e) {
                    last = e;
                }
            }
            final boolean okRemote = remoteOk;
            final JSONObject out = saved;
            final Exception err = last;
            MAIN.post(() -> {
                if (okRemote) {
                    cb.onResult(out, null);
                } else {
                    // 本地已保存成功
                    cb.onResult(out, err != null
                            ? ("已保存到手机；调试台未同步：" + err.getMessage())
                            : "已保存到手机");
                }
            });
        });
    }

    public static void pingAsync() {
        load(null, (json, error) -> {
            if (error != null) {
                Log.w(TAG, "settings ping: " + error);
            }
        });
    }

    public interface HealthCallback {
        void onResult(boolean ok);
    }

    /** 探测调试台 /health 是否可达 */
    public static void pingHealth(HealthCallback cb) {
        EXEC.execute(() -> {
            boolean ok = false;
            for (String base : AppConfig.DEBUG_SERVER_URLS) {
                if (base == null || base.isEmpty()) {
                    continue;
                }
                try {
                    Request req = new Request.Builder()
                            .url(base.replaceAll("/$", "") + "/health")
                            .get()
                            .build();
                    try (Response resp = CLIENT.newCall(req).execute()) {
                        if (resp.isSuccessful()) {
                            ok = true;
                            break;
                        }
                    }
                } catch (Exception ignored) {
                }
            }
            boolean result = ok;
            MAIN.post(() -> {
                if (cb != null) {
                    cb.onResult(result);
                }
            });
        });
    }
}
