/**
 * QueryContent — content register lookup and blob access.
 *
 * Pure functions for reading content attachments from materialized
 * CRDT state and resolving blob bytes from storage.
 */
import ContentAttachmentProjection from "../ContentAttachmentProjection.js";
import QueryError from "../../errors/QueryError.js";
// ── Content attachment projection ───────────────────────────────────
function contentMetaFromRecord(record) {
    return {
        oid: record.payload.oid.toString(),
        mime: record.payload.mime?.toString() ?? null,
        size: record.payload.size?.toNumber() ?? null,
    };
}
function contentOidFromRecord(record) {
    return record.payload.oid.toString();
}
function nodeContentAttachment(state, nodeId) {
    return ContentAttachmentProjection.forNode(state, nodeId);
}
function edgeContentAttachment(state, edge) {
    return ContentAttachmentProjection.forEdge(state, edge);
}
// ── Blob resolution ─────────────────────────────────────────────────
async function resolveBlob(host, oid) {
    if (host._blobStorage) {
        return await host._blobStorage.retrieve(oid);
    }
    return await host._persistence.readBlob(oid);
}
function resolveBlobStream(host, oid) {
    if (host._blobStorage && typeof host._blobStorage.retrieveStream === 'function') {
        return host._blobStorage.retrieveStream(oid);
    }
    return null;
}
export function singleChunkIterable(buf) {
    return {
        [Symbol.asyncIterator]() {
            let done = false;
            return {
                next() {
                    if (done) {
                        return Promise.resolve({ value: undefined, done: true });
                    }
                    done = true;
                    return Promise.resolve({ value: buf, done: false });
                },
            };
        },
    };
}
// ── Host-dependent node content ─────────────────────────────────────
async function ensureAndGetState(host) {
    await host._ensureFreshState();
    if (host._cachedState === null) {
        throw new QueryError('host state is null after _ensureFreshState', { code: 'E_NO_STATE' });
    }
    return host._cachedState;
}
export async function getContentOidImpl(host, nodeId) {
    const state = await ensureAndGetState(host);
    const record = nodeContentAttachment(state, nodeId);
    return record === null ? null : contentOidFromRecord(record);
}
export async function getContentMetaImpl(host, nodeId) {
    const state = await ensureAndGetState(host);
    const record = nodeContentAttachment(state, nodeId);
    return record === null ? null : contentMetaFromRecord(record);
}
export async function getContentImpl(host, nodeId) {
    const state = await ensureAndGetState(host);
    const record = nodeContentAttachment(state, nodeId);
    if (record === null) {
        return null;
    }
    return await resolveBlob(host, contentOidFromRecord(record));
}
export async function getContentStreamImpl(host, nodeId) {
    const state = await ensureAndGetState(host);
    const record = nodeContentAttachment(state, nodeId);
    if (record === null) {
        return null;
    }
    const oid = contentOidFromRecord(record);
    const stream = resolveBlobStream(host, oid);
    if (stream) {
        return stream;
    }
    return singleChunkIterable(await resolveBlob(host, oid));
}
// ── Host-dependent edge content ─────────────────────────────────────
export async function getEdgeContentOidImpl(host, edge) {
    const state = await ensureAndGetState(host);
    const record = edgeContentAttachment(state, edge);
    return record === null ? null : contentOidFromRecord(record);
}
export async function getEdgeContentMetaImpl(host, edge) {
    const state = await ensureAndGetState(host);
    const record = edgeContentAttachment(state, edge);
    return record === null ? null : contentMetaFromRecord(record);
}
export async function getEdgeContentImpl(host, edge) {
    const state = await ensureAndGetState(host);
    const record = edgeContentAttachment(state, edge);
    if (record === null) {
        return null;
    }
    return await resolveBlob(host, contentOidFromRecord(record));
}
export async function getEdgeContentStreamImpl(host, edge) {
    const state = await ensureAndGetState(host);
    const record = edgeContentAttachment(state, edge);
    if (record === null) {
        return null;
    }
    const oid = contentOidFromRecord(record);
    const stream = resolveBlobStream(host, oid);
    if (stream) {
        return stream;
    }
    return singleChunkIterable(await resolveBlob(host, oid));
}
