package com.foxx.androidcast.live;

import android.content.Context;
import android.util.Log;

import com.foxx.androidcast.BuildConfig;
import com.foxx.androidcast.DeviceInfo;
import com.foxx.androidcast.crash.CrashSettingsStore;
import com.foxx.androidcast.network.BackendEndpoints;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/** Keeps BE live cast session state updated (intent/live/closed + 60s keepalive). */
public final class LiveCastControlPlane {
    private static final String TAG = "LiveCastControl";
    private static final int HTTP_TIMEOUT_MS = 20_000;
    private static final long HEARTBEAT_INTERVAL_SEC = 60L;
    private static final AtomicReference<String> SESSION_ID = new AtomicReference<>("");
    private static final ScheduledExecutorService HEARTBEAT = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread t = new Thread(r, "live-cast-heartbeat");
        t.setDaemon(true);
        return t;
    });

    static {
        HEARTBEAT.scheduleAtFixedRate(() -> {
            String sid = SESSION_ID.get();
            if (sid == null || sid.isEmpty()) {
                return;
            }
            try {
                postHeartbeat(sid, "active", "", "", "");
            } catch (Exception e) {
                Log.w(TAG, "heartbeat failed: " + e.getMessage());
            }
        }, HEARTBEAT_INTERVAL_SEC, HEARTBEAT_INTERVAL_SEC, TimeUnit.SECONDS);
    }

    private LiveCastControlPlane() {}

    public static void onCastStart(Context context, String platform, String codecVideo, String codecAudio, String bwMode) {
        if (context == null) {
            return;
        }
        try {
            String sid = SESSION_ID.get();
            if (sid == null || sid.isEmpty()) {
                sid = createIntent(context.getApplicationContext(), platform, codecVideo, codecAudio, bwMode);
                if (sid != null && !sid.isEmpty()) {
                    SESSION_ID.set(sid);
                }
            } else {
                postHeartbeat(sid, "active", codecVideo, codecAudio, bwMode);
            }
        } catch (Exception e) {
            Log.w(TAG, "onCastStart failed: " + e.getMessage());
        }
    }

    public static void onCastStop(String codecVideo, String codecAudio, String bwMode) {
        String sid = SESSION_ID.getAndSet("");
        if (sid == null || sid.isEmpty()) {
            return;
        }
        try {
            postHeartbeat(sid, "ended", codecVideo, codecAudio, bwMode);
        } catch (Exception e) {
            Log.w(TAG, "onCastStop failed: " + e.getMessage());
        }
    }

    private static String createIntent(Context app, String platform, String codecVideo, String codecAudio, String bwMode)
            throws Exception {
        JSONObject req = new JSONObject();
        req.put("action", "create_intent");
        req.put("platform", platform == null || platform.isEmpty() ? "android" : platform);
        req.put("device_id", DeviceInfo.getDeviceUuid(app));
        req.put("max_duration_s", 300);
        if (codecVideo != null && !codecVideo.isEmpty()) {
            req.put("codec_video", codecVideo);
        }
        if (codecAudio != null && !codecAudio.isEmpty()) {
            req.put("codec_audio", codecAudio);
        }
        if (bwMode != null && !bwMode.isEmpty()) {
            req.put("bw_mode", bwMode);
        }
        JSONObject resp = postJson(resolveLiveCastUrl(app), req.toString());
        if (!resp.optBoolean("ok", false)) {
            return "";
        }
        JSONObject session = resp.optJSONObject("session");
        return session != null ? session.optString("session_id", "") : "";
    }

    private static void postHeartbeat(String sid, String status, String codecVideo, String codecAudio, String bwMode)
            throws Exception {
        JSONObject req = new JSONObject();
        req.put("action", "heartbeat");
        req.put("session_id", sid);
        req.put("status", status);
        if (codecVideo != null && !codecVideo.isEmpty()) {
            req.put("codec_video", codecVideo);
        }
        if (codecAudio != null && !codecAudio.isEmpty()) {
            req.put("codec_audio", codecAudio);
        }
        if (bwMode != null && !bwMode.isEmpty()) {
            req.put("bw_mode", bwMode);
        }
        JSONObject resp = postJson(resolveLiveCastUrl(null), req.toString());
        if (!resp.optBoolean("ok", false)) {
            throw new IllegalStateException("heartbeat rejected");
        }
    }

    private static String resolveLiveCastUrl(Context context) {
        String crashesUpload = context != null ? CrashSettingsStore.load(context).uploadUrl : "";
        if (crashesUpload != null && !crashesUpload.trim().isEmpty()) {
            String base = BackendEndpoints.normalizeCrashesUrl(crashesUpload.trim());
            if (base.contains("/api/upload.php")) {
                return base.replace("/api/upload.php", "/api/live_cast.php");
            }
            if (base.endsWith("/")) {
                return base + "api/live_cast.php";
            }
            return base + "/api/live_cast.php";
        }
        return BackendEndpoints.CRASHES_BASE + "/api/live_cast.php";
    }

    private static JSONObject postJson(String url, String body) throws Exception {
        HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();
        c.setRequestMethod("POST");
        c.setConnectTimeout(HTTP_TIMEOUT_MS);
        c.setReadTimeout(HTTP_TIMEOUT_MS);
        c.setDoOutput(true);
        c.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        if (BuildConfig.GIT_COMMIT_SHORT != null) {
            c.setRequestProperty("X-AndroidCast", BuildConfig.GIT_COMMIT_SHORT);
        }
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        try (OutputStream os = c.getOutputStream()) {
            os.write(bytes);
        }
        int code = c.getResponseCode();
        String text = readBody(c);
        c.disconnect();
        if (code < 200 || code >= 300) {
            throw new IllegalStateException("http_" + code + ":" + text);
        }
        return new JSONObject(text);
    }

    private static String readBody(HttpURLConnection c) {
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(c.getInputStream(), StandardCharsets.UTF_8))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
                if (sb.length() > 8192) {
                    break;
                }
            }
            return sb.toString();
        } catch (Exception e) {
            return "";
        }
    }
}

