/**
 * Pure helper functions and types for reading a logical bitmap index.
 *
 * Extracted from LogicalIndexReader to keep each file under 500 LOC
 * and to separate pure query/build logic from the stateful reader class.
 *
 * @module domain/services/index/logicalIndexHelpers
 */
import computeShardKey from "../../utils/shardKey.js";
// ── Shard classification ──────────────────────────────────────────────────────
/**
 * Returns true if the shard path represents a meta file (meta_XX.cbor).
 */
export function isMetaShard(path) {
    return path.startsWith('meta_') && path.endsWith('.cbor');
}
/**
 * Returns true if the shard path represents an edge file (fwd_XX.cbor or rev_XX.cbor).
 */
export function isEdgeShard(path) {
    return path.endsWith('.cbor') && (path.startsWith('fwd_') || path.startsWith('rev_'));
}
/**
 * Classifies loaded path/buf pairs into meta, labels, and edge buckets.
 */
export function classifyShards(items) {
    const meta = [];
    let labels = null;
    const edges = [];
    for (const item of items) {
        const { path } = item;
        if (isMetaShard(path)) {
            meta.push(item);
        }
        else if (path === 'labels.cbor') {
            labels = item.buf;
        }
        else if (isEdgeShard(path)) {
            edges.push(item);
        }
    }
    return { meta, labels, edges };
}
/**
 * Classifies pre-decoded path/data pairs into meta, labels, and edge buckets.
 */
export function classifyDecoded(items) {
    const meta = [];
    let labels = null; // nosemgrep: ts-no-unknown-outside-adapters -- 0025B
    const edges = [];
    for (const item of items) {
        const { path } = item;
        if (isMetaShard(path)) {
            meta.push(item);
        }
        else if (path === 'labels.cbor') {
            labels = item.data;
        }
        else if (isEdgeShard(path)) {
            edges.push(item);
        }
    }
    return { meta, labels, edges };
}
// ── Query helpers ─────────────────────────────────────────────────────────────
/**
 * Expands a bitmap into neighbor entries, pushing into `out`.
 */
function expandBitmap(bitmap, label, ctx) {
    for (const neighborGid of bitmap.toArray()) {
        const neighborId = ctx.g2n.get(neighborGid);
        if (neighborId !== undefined) {
            ctx.out.push({ neighborId, label });
        }
    }
}
/**
 * Resolves edges from a byOwner map for a given node (all labels).
 */
function resolveAllLabels(byOwner, ctx) {
    const { gid, i2l, g2n } = ctx;
    const entries = byOwner.get(gid);
    if (!entries) {
        return [];
    }
    const out = [];
    for (const { labelId, bitmap } of entries) {
        expandBitmap(bitmap, i2l.get(labelId) ?? '', { g2n, out });
    }
    return out;
}
/**
 * Resolves filtered edges for a specific node and direction.
 */
function resolveFilteredEdges(store, ctx) {
    const out = [];
    for (const labelId of ctx.filterLabelIds) {
        const bitmap = store.get(`${ctx.dir}:${labelId}:${ctx.gid}`);
        if (bitmap !== undefined) {
            expandBitmap(bitmap, ctx.i2l.get(labelId) ?? '', { g2n: ctx.g2n, out });
        }
    }
    return out;
}
/**
 * Selects the appropriate edge stores for the given direction.
 */
function selectEdgeStores(maps, dir) {
    return {
        store: dir === 'fwd' ? maps.fwd : maps.rev,
        byOwner: dir === 'fwd' ? maps.byOwnerFwd : maps.byOwnerRev,
    };
}
/**
 * Resolves edges for a specific node and direction from index maps.
 */
export function resolveEdgesForNode(maps, query) {
    const gid = maps.n2g.get(query.nodeId);
    if (gid === undefined) {
        return [];
    }
    const dir = query.direction === 'out' ? 'fwd' : 'rev';
    const { store, byOwner } = selectEdgeStores(maps, dir);
    if (query.filterLabelIds === undefined || query.filterLabelIds === null) {
        return resolveAllLabels(byOwner, { gid, i2l: maps.i2l, g2n: maps.g2n });
    }
    return resolveFilteredEdges(store, { gid, dir, filterLabelIds: query.filterLabelIds, i2l: maps.i2l, g2n: maps.g2n });
}
/**
 * Checks whether a node is alive in the bitmap index.
 */
export function checkAlive(n2g, alive, nodeId) {
    const gid = n2g.get(nodeId);
    if (gid === undefined) {
        return false;
    }
    const bitmap = alive.get(computeShardKey(nodeId));
    return bitmap !== undefined ? bitmap.has(gid) : false;
}
/**
 * Builds a LogicalIndex object from decoded shard maps.
 */
export function buildLogicalIndex(maps) {
    const { n2g, g2n, alive, lr } = maps;
    return {
        getGlobalId: (nodeId) => n2g.get(nodeId),
        getNodeId: (globalId) => g2n.get(globalId),
        getLabelRegistry: () => lr,
        isAlive: (nodeId) => checkAlive(n2g, alive, nodeId),
        getEdges(nodeId, direction, filterLabelIds) {
            const dir = direction;
            return resolveEdgesForNode(maps, { nodeId, direction: dir, ...(filterLabelIds ? { filterLabelIds } : {}) });
        },
    };
}
