package com.foxx.androidcast.crash;

/*********************************************************************
 * CrashReportStore.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
 * class CrashReportStore
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (2 commits, 96 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	7400435fd42c6dca90ddf1cebec7691657b971ec10e059b599aa1287649642e3
**********************************************************************/
import org.json.JSONObject;

import com.foxx.androidcast.util.IoUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/** Pending/uploaded crash JSON in app-private storage (shared across processes). */
public final class CrashReportStore {
    private static final String ROOT = "crash_reports";
    private static final String PENDING = "pending";
    private static final String UPLOADED = "uploaded";
    /** Same stamp as {@code session_send_yyyyMMdd_HHmmss.json} / {@code session_recv_*.json}. */
    public static final String PREFIX = "crash_";
    private static final String SUFFIX = ".json";

    private CrashReportStore() {}

    public static File pendingDir(File filesDir) {
        File dir = new File(new File(filesDir, ROOT), PENDING);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return dir;
    }

    public static File uploadedDir(File filesDir) {
        File dir = new File(new File(filesDir, ROOT), UPLOADED);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return dir;
    }

    public static String formatTimestamp(long epochMs) {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date(epochMs));
    }

    /** {@code crash_yyyyMMdd_HHmmss.json} (suffix {@code _N} if the second collides). */
    public static File newPendingFile(File filesDir, long generatedAtMs) {
        String base = PREFIX + formatTimestamp(generatedAtMs);
        File dir = pendingDir(filesDir);
        File candidate = new File(dir, base + SUFFIX);
        int n = 1;
        while (candidate.exists()) {
            candidate = new File(dir, base + "_" + n + SUFFIX);
            n++;
        }
        return candidate;
    }

    public static void writeJson(File file, JSONObject json) throws Exception {
        File parent = file.getParentFile();
        if (parent != null && !parent.exists()) {
            parent.mkdirs();
        }
        byte[] bytes = json.toString(2).getBytes(StandardCharsets.UTF_8);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(bytes);
        }
    }

    public static JSONObject readJson(File file) {
        try (FileInputStream fis = new FileInputStream(file)) {
            return new JSONObject(new String(IoUtils.readAllBytes(fis), StandardCharsets.UTF_8));
        } catch (Exception e) {
            return null;
        }
    }

    public static List<File> listPending(File filesDir) {
        File dir = pendingDir(filesDir);
        File[] files = dir.listFiles((d, n) -> n.startsWith(PREFIX) && n.endsWith(SUFFIX));
        if (files == null || files.length == 0) {
            return Collections.emptyList();
        }
        List<File> list = new ArrayList<>();
        Collections.addAll(list, files);
        list.sort(Comparator.comparing(File::getName));
        return list;
    }

    public static void markUploaded(File filesDir, File pending, boolean prune) {
        if (prune) {
            pending.delete();
            return;
        }
        File dest = new File(uploadedDir(filesDir), pending.getName());
        pending.renameTo(dest);
    }

    public static void pruneOldestPending(File filesDir, int maxFiles) {
        List<File> pending = listPending(filesDir);
        while (pending.size() > maxFiles) {
            pending.get(0).delete();
            pending = listPending(filesDir);
        }
    }
}
