package com.foxx.androidcast.entitlements;

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

import com.foxx.androidcast.AppPreferences;
import com.foxx.androidcast.network.BackendEndpoints;

import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * Fetches per-account entitlement key + obfuscated blob from BE (RBAC-backed endpoint stub).
 * Returns {@code null} when backend has no payload or network fails — local file remains authoritative.
 */
final class EntitlementSyncClient {
    private static final String TAG = "EntitlementSync";

    static final class SyncPayload {
        final long accountKey;
        final byte[] fileBytes;
        final String etag;

        SyncPayload(long accountKey, byte[] fileBytes, String etag) {
            this.accountKey = accountKey;
            this.fileBytes = fileBytes;
            this.etag = etag != null ? etag : "";
        }
    }

    private EntitlementSyncClient() {}

    static SyncPayload fetch(Context context) {
        String user = AppPreferences.getUsername(context);
        if (user == null || user.trim().isEmpty()) {
            return null;
        }
        HttpURLConnection conn = null;
        try {
            String q = "user=" + URLEncoder.encode(user.trim(), StandardCharsets.UTF_8.name());
            String pin = AppPreferences.getPin(context);
            if (pin != null && !pin.isEmpty()) {
                q += "&pin=" + URLEncoder.encode(pin, StandardCharsets.UTF_8.name());
            }
            URL url = new URL(BackendEndpoints.ENTITLEMENTS_FETCH_URL + "?" + q);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(12_000);
            conn.setReadTimeout(20_000);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "application/json");
            int code = conn.getResponseCode();
            if (code == HttpURLConnection.HTTP_NOT_FOUND) {
                return null;
            }
            if (code != HttpURLConnection.HTTP_OK) {
                Log.w(TAG, "fetch HTTP " + code);
                return null;
            }
            String body = readUtf8(conn.getInputStream());
            JSONObject json = new JSONObject(body);
            String keyHex = json.optString("key", "");
            long key = EntitlementPolicy.parseKeyHex(keyHex);
            if (key == 0L) {
                Log.w(TAG, "fetch missing key");
                return null;
            }
            String fileUrl = json.optString("file_url", "");
            String etag = json.optString("etag", "");
            byte[] bytes;
            if (!fileUrl.isEmpty()) {
                bytes = downloadBytes(fileUrl);
            } else if (json.has("file_base64")) {
                bytes = android.util.Base64.decode(json.getString("file_base64"), android.util.Base64.DEFAULT);
            } else {
                Log.w(TAG, "fetch missing file payload");
                return null;
            }
            if (bytes == null || bytes.length < 16) {
                return null;
            }
            return new SyncPayload(key, bytes, etag);
        } catch (Exception e) {
            Log.w(TAG, "fetch failed: " + e.getMessage());
            return null;
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    static boolean persistPayload(Context context, SyncPayload payload) {
        if (payload == null || payload.fileBytes == null) {
            return false;
        }
        File dest = EntitlementStore.entitlementFile(context);
        File parent = dest.getParentFile();
        if (parent != null && !parent.exists() && !parent.mkdirs()) {
            return false;
        }
        try (FileOutputStream fos = new FileOutputStream(dest, false)) {
            fos.write(payload.fileBytes);
            fos.flush();
        } catch (Exception e) {
            Log.w(TAG, "persist failed: " + e.getMessage());
            return false;
        }
        EntitlementStore.setAccountKey(context, payload.accountKey);
        return true;
    }

    private static byte[] downloadBytes(String fileUrl) throws Exception {
        HttpURLConnection c = (HttpURLConnection) new URL(fileUrl).openConnection();
        c.setConnectTimeout(12_000);
        c.setReadTimeout(30_000);
        try {
            if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return null;
            }
            return readBytes(c.getInputStream());
        } finally {
            c.disconnect();
        }
    }

    private static String readUtf8(InputStream in) throws Exception {
        byte[] raw = readBytes(in);
        return new String(raw, StandardCharsets.UTF_8);
    }

    private static byte[] readBytes(InputStream in) throws Exception {
        try (BufferedInputStream bin = new BufferedInputStream(in);
             ByteArrayOutputStream bout = new ByteArrayOutputStream()) {
            byte[] buf = new byte[4096];
            int n;
            while ((n = bin.read(buf)) >= 0) {
                bout.write(buf, 0, n);
            }
            return bout.toByteArray();
        }
    }
}
