import { createHash } from "node:crypto";
function computeImageId(mimeType, data) {
    return createHash("sha256").update(mimeType).update("\0").update(data).digest("hex");
}
function isPlainObject(x) {
    if (x === null || typeof x !== "object") {
        return false;
    }
    if (Array.isArray(x)) {
        return false;
    }
    const proto = Object.getPrototypeOf(x);
    return proto === Object.prototype || proto === null;
}
function isImageObject(x) {
    if (!isPlainObject(x)) {
        return false;
    }
    return x.type === "image" && typeof x.data === "string" && typeof x.mimeType === "string";
}
export class ImagePayloadCache {
    byId = new Map();
    get(imageId) {
        return this.byId.get(imageId);
    }
    materializePeerPayload(value) {
        const images = [];
        const seenInCall = new Set();
        const result = this.transformValue(value, images, seenInCall);
        return { value: result, images };
    }
    transformValue(value, images, seenInCall) {
        if (value === null || typeof value !== "object") {
            return value;
        }
        if (Array.isArray(value)) {
            return this.transformArray(value, images, seenInCall);
        }
        if (isImageObject(value)) {
            return this.replaceImageNode(value, images, seenInCall);
        }
        if (isPlainObject(value)) {
            return this.transformPlainObject(value, images, seenInCall);
        }
        return value;
    }
    transformArray(value, images, seenInCall) {
        let changed = false;
        const out = new Array(value.length);
        for (let i = 0; i < value.length; i++) {
            const el = value[i];
            const next = this.transformValue(el, images, seenInCall);
            if (next !== el) {
                changed = true;
            }
            out[i] = next;
        }
        return changed ? out : value;
    }
    transformPlainObject(x, images, seenInCall) {
        let changed = false;
        const result = {};
        for (const k of Object.keys(x)) {
            const el = x[k];
            const next = this.transformValue(el, images, seenInCall);
            if (next !== el) {
                changed = true;
            }
            result[k] = next;
        }
        return changed ? result : x;
    }
    replaceImageNode(node, images, seenInCall) {
        const { mimeType, data } = node;
        const imageId = computeImageId(mimeType, data);
        const payload = { imageId, mimeType, data };
        this.byId.set(imageId, payload);
        if (!seenInCall.has(imageId)) {
            seenInCall.add(imageId);
            images.push(payload);
        }
        return { ...node, data: "", imageId };
    }
}
//# sourceMappingURL=image-payload-cache.js.map