import { createInitialNativeDirectScalarBatch, MAX_INITIAL_NATIVE_DIRECT_SCALAR_BATCH_SIZE, MIN_INITIAL_NATIVE_DIRECT_SCALAR_BATCH_SIZE, } from './formula-initialization-native-direct-scalar.js';
function operandCanUseChunk(operand, selectedCells, cellFlags) {
    switch (operand.kind) {
        case 'literal-number':
        case 'error':
            return true;
        case 'cell':
            return selectedCells.has(operand.cellIndex) || ((cellFlags[operand.cellIndex] ?? 0) & 2 /* CellFlags.HasFormula */) === 0;
    }
}
function formulaCanUseChunk(directScalar, selectedCells, cellFlags) {
    if (directScalar.kind === 'abs') {
        return operandCanUseChunk(directScalar.operand, selectedCells, cellFlags);
    }
    return operandCanUseChunk(directScalar.left, selectedCells, cellFlags) && operandCanUseChunk(directScalar.right, selectedCells, cellFlags);
}
function materializeChunkPlans(args) {
    const chunks = [];
    let current = [];
    let selectedCells = new Set();
    const flushCurrent = () => {
        if (current.length >= args.minChunkSize) {
            chunks.push({ candidates: current });
        }
        current = [];
        selectedCells = new Set();
    };
    for (const candidate of args.candidates) {
        if (current.length === args.maxChunkSize) {
            flushCurrent();
        }
        const directScalar = candidate.runtimeFormula.directScalar;
        if (!directScalar ||
            candidate.runtimeFormula.compiled.volatile ||
            candidate.runtimeFormula.compiled.producesSpill ||
            !formulaCanUseChunk(directScalar, selectedCells, args.cellFlags)) {
            continue;
        }
        current.push(candidate);
        selectedCells.add(candidate.cellIndex);
    }
    flushCurrent();
    return chunks;
}
export function createInitialDirectScalarRunChunkCollector(args) {
    const minChunkSize = args.options?.minChunkSize ?? MIN_INITIAL_NATIVE_DIRECT_SCALAR_BATCH_SIZE;
    const maxChunkSize = args.options?.maxChunkSize ?? MAX_INITIAL_NATIVE_DIRECT_SCALAR_BATCH_SIZE;
    const candidates = [];
    let chunks;
    const chunkPlans = () => {
        if (chunks) {
            return chunks;
        }
        chunks = materializeChunkPlans({
            candidates,
            cellFlags: args.state.workbook.cellStore.flags,
            minChunkSize,
            maxChunkSize,
        });
        return chunks;
    };
    return {
        get candidateCount() {
            return candidates.length;
        },
        add(candidate) {
            if (!candidate.runtimeFormula.directScalar) {
                return false;
            }
            candidates.push(candidate);
            chunks = undefined;
            return true;
        },
        hasNativeChunks() {
            return chunkPlans().length > 0;
        },
        evaluate() {
            const plans = chunkPlans();
            if (plans.length === 0) {
                return undefined;
            }
            const changedChunks = [];
            let changedCellCount = 0;
            for (const plan of plans) {
                const batch = createInitialNativeDirectScalarBatch({
                    state: args.state,
                    capacity: plan.candidates.length,
                });
                let addedAll = true;
                for (const candidate of plan.candidates) {
                    const directScalar = candidate.runtimeFormula.directScalar;
                    if (!directScalar ||
                        !batch.add({
                            cellIndex: candidate.cellIndex,
                            sheetId: candidate.sheetId,
                            col: candidate.col,
                        }, directScalar)) {
                        addedAll = false;
                        break;
                    }
                }
                if (!addedAll) {
                    continue;
                }
                const changedCells = batch.evaluate();
                if (!changedCells || changedCells.length === 0) {
                    continue;
                }
                changedChunks.push(changedCells);
                changedCellCount += changedCells.length;
            }
            if (changedCellCount === 0) {
                return undefined;
            }
            if (changedChunks.length === 1) {
                return changedChunks[0];
            }
            const changedCells = new Uint32Array(changedCellCount);
            let offset = 0;
            for (const chunk of changedChunks) {
                changedCells.set(chunk, offset);
                offset += chunk.length;
            }
            return changedCells;
        },
    };
}
//# sourceMappingURL=formula-initialization-direct-scalar-run-chunks.js.map