package com.foxx.androidcast.ota;

/*********************************************************************
 * OtaJsonFetch.java
 * Created at: Wed 20 May 2026 14:31:55 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (2 commits, 122 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	fc9897e4627ffc8405f8deeeefbc17d085cb1b960695ca41929b8c073c36a9fb
**********************************************************************/
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Locale;

/** Small HTTP JSON helper for OTA endpoints. */
final class OtaJsonFetch {
    private static final int CONNECT_TIMEOUT_MS = 12_000;
    private static final int READ_TIMEOUT_MS = 20_000;

    private OtaJsonFetch() {}

    static JSONObject getJson(String url, int maxBytes) throws Exception {
        byte[] body = getBytes(url, maxBytes);
        return new JSONObject(new String(body, StandardCharsets.UTF_8));
    }

    static byte[] getBytes(String url, int maxBytes) throws Exception {
        String scheme = schemeOf(url);
        if ("mqtt".equals(scheme) || "mqtts".equals(scheme)) {
            byte[] body = OtaMqttFetch.getPayload(url, READ_TIMEOUT_MS);
            if (body.length > maxBytes) {
                throw new IllegalStateException("Response too large");
            }
            return body;
        }
        if (!isHttpUrl(url)) {
            throw new IllegalStateException("Unsupported OTA scheme: " + scheme);
        }
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
        conn.setReadTimeout(READ_TIMEOUT_MS);
        conn.setInstanceFollowRedirects(true);
        conn.setRequestProperty("Accept", "application/json");
        int code = conn.getResponseCode();
        InputStream in = code >= 200 && code < 300 ? conn.getInputStream() : conn.getErrorStream();
        if (in == null) {
            conn.disconnect();
            throw new IllegalStateException("HTTP " + code);
        }
        byte[] body = readLimited(in, maxBytes);
        conn.disconnect();
        if (code < 200 || code >= 300) {
            throw new IllegalStateException("HTTP " + code);
        }
        return body;
    }

    static long getContentLength(String url) {
        String scheme = schemeOf(url);
        if ("mqtt".equals(scheme) || "mqtts".equals(scheme)) {
            return 0L;
        }
        if (!isHttpUrl(url)) {
            return 0L;
        }
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
            conn.setReadTimeout(READ_TIMEOUT_MS);
            conn.setInstanceFollowRedirects(true);
            conn.setRequestMethod("HEAD");
            long len = conn.getContentLengthLong();
            if (len > 0L) {
                return len;
            }
        } catch (Exception ignored) {
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return 0L;
    }

    static String schemeOf(String url) {
        try {
            URI uri = URI.create(url);
            String scheme = uri.getScheme();
            return scheme == null ? "" : scheme.toLowerCase(Locale.US);
        } catch (Exception ignored) {
            return "";
        }
    }

    static boolean isHttpUrl(String url) {
        String scheme = schemeOf(url);
        return "http".equals(scheme) || "https".equals(scheme);
    }

    private static byte[] readLimited(InputStream in, int maxBytes) throws Exception {
        try (BufferedInputStream bin = new BufferedInputStream(in);
                ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            byte[] buf = new byte[4096];
            int total = 0;
            int n;
            while ((n = bin.read(buf)) != -1) {
                total += n;
                if (total > maxBytes) {
                    throw new IllegalStateException("Response too large");
                }
                out.write(buf, 0, n);
            }
            return out.toByteArray();
        }
    }
}
