/**
 * WarpStateIndexBuilder - Builds bitmap index from materialized WARP state.
 *
 * This builder creates adjacency indexes from WarpState.edgeAlive OR-Set,
 * NOT from Git commit DAG topology. This is the correct WARP architecture
 * as specified in the historical index-builder technical spec.
 *
 * The index supports O(1) neighbor lookups by node ID.
 *
 * @module domain/services/index/WarpStateIndexBuilder
 */
import BitmapIndexBuilder from "./BitmapIndexBuilder.js";
import { decodeEdgeKey } from "../KeyCodec.js";
import IndexError from "../../errors/IndexError.js";
import WarpState from "../state/WarpState.js";
import { collectAliveNodeIdsFromSession, collectVisibleEdgesFromSession, } from "../state/SessionVisibleGraph.js";
function validateWarpState(state) {
    if (!(state instanceof WarpState)) {
        throw new IndexError('Invalid state: must be a valid WarpState object', { code: 'E_INDEX_INVALID_STATE' });
    }
    return state;
}
/**
 * Builds a bitmap index from materialized WARP state.
 *
 * This is the compliant index builder that operates on logical graph edges
 * from the edgeAlive OR-Set, not Git commit parents.
 *
 * @example
 * const state = await graph.materialize();
 * const builder = new WarpStateIndexBuilder();
 * const indexData = builder.buildFromState(state);
 */
export default class WarpStateIndexBuilder {
    _builder;
    constructor(_options) {
        this._builder = new BitmapIndexBuilder();
    }
    /**
     * Builds an index from materialized WARP state.
     *
     * Iterates over edgeAlive OR-Set and creates forward/reverse adjacency
     * bitmaps for each node. Only includes edges where both endpoints are
     * visible (exist in nodeAlive).
     *
     * @returns The populated builder and stats
     * @throws {IndexError} If state is null or missing nodeAlive/edgeAlive fields
     */
    buildFromState(state) {
        const validState = validateWarpState(state);
        const nodeCount = this._registerNodes(validState);
        const edgeCount = this._indexEdges(validState);
        return {
            builder: this._builder,
            stats: { nodes: nodeCount, edges: edgeCount },
        };
    }
    async buildFromSession(session) {
        const aliveNodes = await collectAliveNodeIdsFromSession(session);
        const visibleEdges = await collectVisibleEdgesFromSession(session, new Set(aliveNodes));
        const nodeCount = this._registerNodeIds(aliveNodes);
        const edgeCount = this._indexVisibleEdges(visibleEdges);
        return {
            builder: this._builder,
            stats: { nodes: nodeCount, edges: edgeCount },
        };
    }
    _registerNodes(state) {
        return this._registerNodeIds(state.nodeAlive.elements());
    }
    _indexEdges(state) {
        const aliveNodes = state.nodeAlive.elements();
        const aliveNodeSet = new Set(aliveNodes);
        const visibleEdges = [];
        for (const edgeKey of state.edgeAlive.elements()) {
            const edge = decodeEdgeKey(edgeKey);
            if (!aliveNodeSet.has(edge.from) || !aliveNodeSet.has(edge.to)) {
                continue;
            }
            visibleEdges.push(edge);
        }
        return this._indexVisibleEdges(visibleEdges);
    }
    _registerNodeIds(nodeIds) {
        let count = 0;
        for (const nodeId of nodeIds) {
            this._builder.registerNode(nodeId);
            count += 1;
        }
        return count;
    }
    _indexVisibleEdges(edges) {
        let count = 0;
        for (const edge of edges) {
            this._builder.addEdge(edge.from, edge.to);
            count += 1;
        }
        return count;
    }
    /**
     * Serializes the index to a tree structure of buffers.
     */
    serialize() {
        return this._builder.serialize();
    }
    /**
     * Gets the underlying BitmapIndexBuilder.
     */
    get builder() {
        return this._builder;
    }
}
/**
 * Convenience function to build and serialize a WARP state index.
 */
export function buildWarpStateIndex(state, options) {
    const indexBuilder = new WarpStateIndexBuilder(options !== undefined ? options : {});
    const { stats } = indexBuilder.buildFromState(state);
    const tree = indexBuilder.serialize();
    return { tree, stats };
}
export async function buildWarpStateIndexFromSession(session, options) {
    const indexBuilder = new WarpStateIndexBuilder(options !== undefined ? options : {});
    const { stats } = await indexBuilder.buildFromSession(session);
    const tree = indexBuilder.serialize();
    return { tree, stats };
}
