import { MapDef } from "@lodestar/utils";
import { PendingBlockInputStatus, getBlockInputSyncCacheItemRootHex, isPendingBlockInput, } from "../types.js";
export function getAllDescendantBlocks(blockRootHex, blocks) {
    // Do one pass over all blocks to index by parent
    const byParent = new MapDef(() => []);
    for (const block of blocks.values()) {
        if (isPendingBlockInput(block)) {
            byParent.getOrDefault(block.blockInput.parentRootHex).push(block);
        }
    }
    // Then, do a second pass recursively to get `blockRootHex` child blocks
    return addToDescendantBlocks(blockRootHex, byParent);
}
/** Recursive function for `getAllDescendantBlocks()` */
function addToDescendantBlocks(childBlockRootHex, byParent, descendantBlocks = []) {
    const firstDescendantBlocks = byParent.get(childBlockRootHex);
    if (firstDescendantBlocks) {
        for (const firstDescendantBlock of firstDescendantBlocks) {
            descendantBlocks.push(firstDescendantBlock);
            addToDescendantBlocks(getBlockInputSyncCacheItemRootHex(firstDescendantBlock), byParent, descendantBlocks);
        }
    }
    return descendantBlocks;
}
export function getDescendantBlocks(blockRootHex, blocks) {
    const descendantBlocks = [];
    for (const block of blocks.values()) {
        if ((isPendingBlockInput(block) ? block.blockInput.parentRootHex : undefined) === blockRootHex) {
            descendantBlocks.push(block);
        }
    }
    return descendantBlocks;
}
/**
 * Returns two arrays.
 * The first one has the earliest blocks that are not linked to fork-choice yet, meaning they require parent blocks to be pulled.
 * The second one has the earliest blocks that are linked to fork-choice, meaning they are ready to be processed.
 *
 * Given this chain segment unknown block n => downloaded block n + 1 => downloaded block n + 2
 *   return `{incomplete: [n], ancestors: []}`
 *
 * Given this chain segment: downloaded block n => downloaded block n + 1 => downloaded block n + 2
 *   return {incomplete: [], ancestors: [n]}
 */
export function getUnknownAndAncestorBlocks(blocks) {
    const unknowns = new Map();
    const ancestors = new Map();
    for (const block of blocks.values()) {
        if (block.status === PendingBlockInputStatus.pending &&
            (isPendingBlockInput(block) ? !block.blockInput.hasBlockAndAllData() : true)) {
            unknowns.set(getBlockInputSyncCacheItemRootHex(block), block);
        }
        else if (isPendingBlockInput(block) &&
            block.status === PendingBlockInputStatus.downloaded &&
            !blocks.has(block.blockInput.parentRootHex)) {
            ancestors.set(block.blockInput.blockRootHex, block);
        }
    }
    return {
        unknowns: Array.from(unknowns.values()),
        ancestors: Array.from(ancestors.values()),
    };
}
//# sourceMappingURL=pendingBlocksTree.js.map