// png-json-metadata.ts
import * as fs from "fs";
import extract from "png-chunks-extract";
import encodeChunks from "png-chunks-encode";
import * as textChunk from "png-chunk-text";

type PngChunk = { name: string; data: Uint8Array };

/**
 * PNG へ JSON を Base64 で埋め込む（tEXt / keyword: "json-b64"）
 * - JSON は UTF-8 → Base64 にして ASCII 化（tEXt の Latin-1 制限を回避）
 * - 既存の "json-b64" tEXt があれば置き換え（重複回避）
 */
export async function embedJsonToPng(path: string, obj: unknown): Promise<void> {
    const input = fs.readFileSync(path);
    const chunks = extract(input) as PngChunk[];

    // 既存の "json-b64" tEXt を除外
    const filtered: PngChunk[] = chunks.filter((c) => {
        if (c.name !== "tEXt") return true;
        try {
            const decoded = textChunk.decode(c.data); // { keyword, text }
            return decoded.keyword !== "json-b64";
        } catch {
            // decode 失敗（別の形式など）は残す
            return true;
        }
    });

    const json = JSON.stringify(obj);
    const b64 = Buffer.from(json, "utf8").toString("base64"); // ASCII のみ

    // encode() は { name:'tEXt', data: Uint8Array } を返す
    const newChunk = textChunk.encode("json-b64", b64) as PngChunk;

    // IEND の直前に挿入（PNG の正しい順序を維持）
    const iendIndex = filtered.findIndex((c) => c.name === "IEND");
    if (iendIndex < 0) {
        throw new Error("Invalid PNG: missing IEND chunk.");
    }
    filtered.splice(iendIndex, 0, newChunk);

    const out = Buffer.from(encodeChunks(filtered));
    fs.writeFileSync(path, out);
}

/**
 * PNG から Base64 JSON（tEXt / keyword: "json-b64"）を読み出す
 */
export async function readJsonToPng(path: string): Promise<any> {
    const input = fs.readFileSync(path);
    const chunks = extract(input) as PngChunk[];

    for (const c of chunks) {
        if (c.name !== "tEXt") continue;
        try {
            const { keyword, text } = textChunk.decode(c.data);
            if (keyword === "json-b64") {
                const json = Buffer.from(text, "base64").toString("utf8");
                return JSON.parse(json);
            }
        } catch {
            // 他の tEXt / 壊れたエントリは無視
        }
    }
    throw new Error("No base64 JSON found in PNG (tEXt keyword 'json-b64').");
}
