import { Effect } from 'effect';
import { ErrorCode, MAX_COLS, MAX_ROWS, ValueTag } from '@bilig/protocol';
import { formatAddress, parseCellAddress } from '@bilig/formula';
import { entityPayload, isRangeEntity, makeCellEntity, makeRangeEntity } from '../../entity-ids.js';
import { appendPackedCellIndex } from '../../engine-buffer-utils.js';
import { areCellValuesEqual, emptyValue, errorValue } from '../../engine-value-utils.js';
import { EngineMutationError } from '../errors.js';
import { createMutationSupportChangeSetTracker } from './mutation-support-change-sets.js';
function mutationErrorMessage(message, cause) {
    return cause instanceof Error && cause.message.length > 0 ? cause.message : message;
}
function removePackedCellIndex(indices, cellIndex) {
    let found = false;
    const next = new Uint32Array(indices.length);
    let cursor = 0;
    for (let index = 0; index < indices.length; index += 1) {
        const current = indices[index];
        if (current === cellIndex) {
            found = true;
            continue;
        }
        next[cursor] = current;
        cursor += 1;
    }
    return found ? next.subarray(0, cursor) : indices;
}
export function createEngineMutationSupportService(args) {
    const getReverseEdgeSlice = (entityId) => {
        if (isRangeEntity(entityId)) {
            return args.reverseState.reverseRangeEdges[entityPayload(entityId)];
        }
        return args.reverseState.reverseCellEdges[entityPayload(entityId)];
    };
    const setReverseEdgeSlice = (entityId, slice) => {
        const empty = slice.ptr < 0 || slice.len === 0;
        if (isRangeEntity(entityId)) {
            args.reverseState.reverseRangeEdges[entityPayload(entityId)] = empty ? undefined : slice;
            return;
        }
        args.reverseState.reverseCellEdges[entityPayload(entityId)] = empty ? undefined : slice;
    };
    const appendReverseEdge = (entityId, dependentEntityId) => {
        const slice = getReverseEdgeSlice(entityId) ?? args.edgeArena.empty();
        setReverseEdgeSlice(entityId, args.edgeArena.appendUnique(slice, dependentEntityId));
    };
    const removeReverseEdge = (entityId, dependentEntityId) => {
        const slice = getReverseEdgeSlice(entityId);
        if (!slice) {
            return;
        }
        setReverseEdgeSlice(entityId, args.edgeArena.removeValue(slice, dependentEntityId));
    };
    const getEntityDependents = (entityId) => args.edgeArena.readView(getReverseEdgeSlice(entityId) ?? args.edgeArena.empty());
    const blockedSpillBlockersByOwner = new Map();
    const changeSets = createMutationSupportChangeSetTracker({
        formulas: args.state.formulas,
        ...(args.getVolatileFormulaCellIndices ? { getVolatileFormulaCellIndices: args.getVolatileFormulaCellIndices } : {}),
        ensureRecalcScratchCapacity: args.ensureRecalcScratchCapacity,
        getCellStoreSize: () => args.state.workbook.cellStore.size,
        getChangedInputEpoch: args.getChangedInputEpoch,
        setChangedInputEpoch: args.setChangedInputEpoch,
        getChangedInputSeen: args.getChangedInputSeen,
        getChangedInputBuffer: args.getChangedInputBuffer,
        getChangedFormulaEpoch: args.getChangedFormulaEpoch,
        setChangedFormulaEpoch: args.setChangedFormulaEpoch,
        getChangedFormulaSeen: args.getChangedFormulaSeen,
        getChangedFormulaBuffer: args.getChangedFormulaBuffer,
        getChangedUnionEpoch: args.getChangedUnionEpoch,
        setChangedUnionEpoch: args.setChangedUnionEpoch,
        getChangedUnionSeen: args.getChangedUnionSeen,
        getChangedUnion: args.getChangedUnion,
        getMutationRoots: args.getMutationRoots,
        getMaterializedCellCount: args.getMaterializedCellCount,
        setMaterializedCellCount: args.setMaterializedCellCount,
        getMaterializedCells: args.getMaterializedCells,
        setMaterializedCells: args.setMaterializedCells,
        getExplicitChangedEpoch: args.getExplicitChangedEpoch,
        setExplicitChangedEpoch: args.setExplicitChangedEpoch,
        getExplicitChangedSeen: args.getExplicitChangedSeen,
        getExplicitChangedBuffer: args.getExplicitChangedBuffer,
    });
    const { beginMutationCollectionNow, markInputChangedNow, markFormulaChangedNow, markExplicitChangedNow, markVolatileFormulasChangedNow, composeMutationRootsNow, composeEventChangesNow, composeDisjointEventChangesNow, unionChangedSetsNow, composeChangedRootsAndOrderedNow, getChangedInputBufferNow, pushMaterializedCell, resetMaterializedCellScratchNow, } = changeSets;
    const ensureCellTrackedNow = (sheetName, address) => {
        const ensured = args.state.workbook.ensureCellRecord(sheetName, address);
        if (ensured.created) {
            pushMaterializedCell(ensured.cellIndex);
        }
        return ensured.cellIndex;
    };
    const ensureCellTrackedByCoordsNow = (sheetId, row, col) => {
        const ensured = args.state.workbook.ensureCellAt(sheetId, row, col);
        if (ensured.created) {
            pushMaterializedCell(ensured.cellIndex);
        }
        return ensured.cellIndex;
    };
    const clearSpillChildCell = (cellIndex) => {
        const currentFlags = args.state.workbook.cellStore.flags[cellIndex] ?? 0;
        const currentValue = args.state.workbook.cellStore.getValue(cellIndex, (id) => args.state.strings.get(id));
        if (currentValue.tag === ValueTag.Empty && (currentFlags & 64 /* CellFlags.SpillChild */) === 0) {
            return false;
        }
        args.state.workbook.cellStore.setValue(cellIndex, emptyValue());
        args.state.workbook.cellStore.flags[cellIndex] = currentFlags & ~64 /* CellFlags.SpillChild */;
        return true;
    };
    const setSpillChildValue = (cellIndex, value) => {
        const currentValue = args.state.workbook.cellStore.getValue(cellIndex, (id) => args.state.strings.get(id));
        const currentFlags = args.state.workbook.cellStore.flags[cellIndex] ?? 0;
        const nextFlags = (currentFlags & ~(2 /* CellFlags.HasFormula */ | 4 /* CellFlags.JsOnly */ | 8 /* CellFlags.InCycle */)) | 64 /* CellFlags.SpillChild */;
        if (areCellValuesEqual(currentValue, value) && currentFlags === nextFlags) {
            return false;
        }
        args.state.workbook.cellStore.setValue(cellIndex, value, value.tag === ValueTag.String ? args.state.strings.intern(value.value) : 0);
        args.state.workbook.cellStore.flags[cellIndex] = nextFlags;
        return true;
    };
    const clearBlockedSpillObstructionsForOwner = (ownerCellIndex) => {
        const blockers = blockedSpillBlockersByOwner.get(ownerCellIndex);
        if (!blockers) {
            return;
        }
        const formula = args.state.formulas.get(ownerCellIndex);
        const formulaEntity = makeCellEntity(ownerCellIndex);
        blockers.forEach((blockerCellIndex) => {
            const blockerEntity = makeCellEntity(blockerCellIndex);
            removeReverseEdge(blockerEntity, formulaEntity);
            if (formula) {
                formula.dependencyIndices = removePackedCellIndex(formula.dependencyIndices, blockerCellIndex);
                formula.dependencyEntities = args.edgeArena.removeValue(formula.dependencyEntities, blockerEntity);
            }
        });
        blockedSpillBlockersByOwner.delete(ownerCellIndex);
    };
    const clearOwnedSpillNow = (cellIndex) => {
        clearBlockedSpillObstructionsForOwner(cellIndex);
        const sheetName = args.state.workbook.getSheetNameById(args.state.workbook.cellStore.sheetIds[cellIndex]);
        const address = args.state.workbook.getAddress(cellIndex);
        const spill = args.state.workbook.getSpill(sheetName, address);
        if (!spill) {
            return [];
        }
        const owner = parseCellAddress(address, sheetName);
        const changedCellIndices = [];
        for (let rowOffset = 0; rowOffset < spill.rows; rowOffset += 1) {
            for (let colOffset = 0; colOffset < spill.cols; colOffset += 1) {
                if (rowOffset === 0 && colOffset === 0) {
                    continue;
                }
                const childAddress = formatAddress(owner.row + rowOffset, owner.col + colOffset);
                const childIndex = args.state.workbook.getCellIndex(sheetName, childAddress);
                if (childIndex === undefined) {
                    continue;
                }
                if (clearSpillChildCell(childIndex)) {
                    changedCellIndices.push(childIndex);
                }
            }
        }
        changedCellIndices.push(...args.applyDerivedOp({ kind: 'deleteSpillRange', sheetName, address }));
        return changedCellIndices;
    };
    const findContainingSpillNow = (cellIndex) => {
        const sheetId = args.state.workbook.cellStore.sheetIds[cellIndex];
        if (sheetId === undefined) {
            return undefined;
        }
        const sheetName = args.state.workbook.getSheetNameById(sheetId);
        const position = args.state.workbook.getCellPosition(cellIndex);
        const row = position?.row ?? args.state.workbook.cellStore.rows[cellIndex] ?? 0;
        const col = position?.col ?? args.state.workbook.cellStore.cols[cellIndex] ?? 0;
        for (const spill of args.state.workbook.listSpills()) {
            if (spill.sheetName !== sheetName) {
                continue;
            }
            const owner = parseCellAddress(spill.address, spill.sheetName);
            if (row < owner.row || row >= owner.row + spill.rows || col < owner.col || col >= owner.col + spill.cols) {
                continue;
            }
            return {
                sheetName,
                address: spill.address,
                ownerCellIndex: args.state.workbook.getCellIndex(sheetName, spill.address),
                ownerRow: owner.row,
                ownerCol: owner.col,
                rows: spill.rows,
                cols: spill.cols,
            };
        }
        return undefined;
    };
    const clearSpillForCellNow = (cellIndex) => {
        const spill = findContainingSpillNow(cellIndex);
        if (!spill) {
            return { changedCellIndices: [], ownerCellIndex: undefined };
        }
        if (spill.ownerCellIndex === cellIndex) {
            return { changedCellIndices: clearOwnedSpillNow(cellIndex), ownerCellIndex: undefined };
        }
        const changedCellIndices = [];
        for (let rowOffset = 0; rowOffset < spill.rows; rowOffset += 1) {
            for (let colOffset = 0; colOffset < spill.cols; colOffset += 1) {
                if (rowOffset === 0 && colOffset === 0) {
                    continue;
                }
                const childAddress = formatAddress(spill.ownerRow + rowOffset, spill.ownerCol + colOffset);
                const childIndex = args.state.workbook.getCellIndex(spill.sheetName, childAddress);
                if (childIndex === undefined || childIndex === cellIndex) {
                    continue;
                }
                if (clearSpillChildCell(childIndex)) {
                    changedCellIndices.push(childIndex);
                }
            }
        }
        changedCellIndices.push(...args.applyDerivedOp({ kind: 'deleteSpillRange', sheetName: spill.sheetName, address: spill.address }));
        return { changedCellIndices, ownerCellIndex: spill.ownerCellIndex };
    };
    const trackSpillObstructionDependency = (ownerCellIndex, blockerCellIndex) => {
        const formula = args.state.formulas.get(ownerCellIndex);
        if (!formula) {
            return;
        }
        let blockers = blockedSpillBlockersByOwner.get(ownerCellIndex);
        if (!blockers) {
            blockers = new Set();
            blockedSpillBlockersByOwner.set(ownerCellIndex, blockers);
        }
        blockers.add(blockerCellIndex);
        const blockerEntity = makeCellEntity(blockerCellIndex);
        const formulaEntity = makeCellEntity(ownerCellIndex);
        formula.dependencyIndices = appendPackedCellIndex(formula.dependencyIndices, blockerCellIndex);
        formula.dependencyEntities = args.edgeArena.appendUnique(formula.dependencyEntities, blockerEntity);
        appendReverseEdge(blockerEntity, formulaEntity);
    };
    const materializeSpillNow = (cellIndex, arrayValue) => {
        const changedCellIndices = clearOwnedSpillNow(cellIndex);
        const sheetId = args.state.workbook.cellStore.sheetIds[cellIndex];
        const sheetName = args.state.workbook.getSheetNameById(sheetId);
        const address = args.state.workbook.getAddress(cellIndex);
        const owner = parseCellAddress(address, sheetName);
        if (owner.row + arrayValue.rows > MAX_ROWS || owner.col + arrayValue.cols > MAX_COLS) {
            return { changedCellIndices, ownerValue: errorValue(ErrorCode.Spill) };
        }
        for (let rowOffset = 0; rowOffset < arrayValue.rows; rowOffset += 1) {
            for (let colOffset = 0; colOffset < arrayValue.cols; colOffset += 1) {
                if (rowOffset === 0 && colOffset === 0) {
                    continue;
                }
                const targetAddress = formatAddress(owner.row + rowOffset, owner.col + colOffset);
                const targetIndex = args.state.workbook.getCellIndex(sheetName, targetAddress);
                if (targetIndex === undefined) {
                    continue;
                }
                const targetValue = args.state.workbook.cellStore.getValue(targetIndex, (id) => args.state.strings.get(id));
                if (args.state.formulas.get(targetIndex) || targetValue.tag !== ValueTag.Empty) {
                    trackSpillObstructionDependency(cellIndex, targetIndex);
                    changedCellIndices.push(...args.applyDerivedOp({ kind: 'upsertSpillRange', sheetName, address, rows: 1, cols: 1 }));
                    return { changedCellIndices, ownerValue: errorValue(ErrorCode.Spill) };
                }
            }
        }
        for (let rowOffset = 0; rowOffset < arrayValue.rows; rowOffset += 1) {
            for (let colOffset = 0; colOffset < arrayValue.cols; colOffset += 1) {
                if (rowOffset === 0 && colOffset === 0) {
                    continue;
                }
                const targetIndex = ensureCellTrackedByCoordsNow(sheetId, owner.row + rowOffset, owner.col + colOffset);
                const valueIndex = rowOffset * arrayValue.cols + colOffset;
                const value = arrayValue.values[valueIndex] ?? emptyValue();
                if (setSpillChildValue(targetIndex, value)) {
                    changedCellIndices.push(targetIndex);
                }
            }
        }
        changedCellIndices.push(...args.applyDerivedOp({
            kind: 'upsertSpillRange',
            sheetName,
            address,
            rows: arrayValue.rows,
            cols: arrayValue.cols,
        }));
        return {
            changedCellIndices,
            ownerValue: arrayValue.values[0] ?? emptyValue(),
        };
    };
    const removeSheetRuntimeNow = (sheetName, explicitChangedCount) => {
        const sheet = args.state.workbook.getSheet(sheetName);
        if (!sheet) {
            return { changedInputCount: 0, formulaChangedCount: 0, explicitChangedCount };
        }
        const cellIndices = [];
        sheet.grid.forEachCell((cellIndex) => {
            cellIndices.push(cellIndex);
        });
        let changedInputCount = 0;
        let formulaChangedCount = 0;
        cellIndices.forEach((cellIndex) => {
            args.removeFormula(cellIndex);
            setReverseEdgeSlice(makeCellEntity(cellIndex), args.edgeArena.empty());
            args.state.workbook.cellStore.setValue(cellIndex, emptyValue());
            args.state.workbook.cellStore.flags[cellIndex] = (args.state.workbook.cellStore.flags[cellIndex] ?? 0) | 32 /* CellFlags.PendingDelete */;
            changedInputCount = markInputChangedNow(cellIndex, changedInputCount);
            explicitChangedCount = markExplicitChangedNow(cellIndex, explicitChangedCount);
        });
        args.state.workbook.deleteSheet(sheetName);
        if (args.getSelectionState().sheetName === sheetName) {
            const nextSheet = [...args.state.workbook.sheetsByName.values()].toSorted((left, right) => left.order - right.order)[0];
            args.setSelection(nextSheet?.name ?? sheetName, 'A1');
        }
        formulaChangedCount = args.rebindFormulasForSheet(sheetName, formulaChangedCount);
        return { changedInputCount, formulaChangedCount, explicitChangedCount };
    };
    const syncDynamicRangesNow = (formulaChangedCount) => {
        for (let index = 0; index < args.getMaterializedCellCount(); index += 1) {
            const cellIndex = args.getMaterializedCells()[index];
            const sheetId = args.state.workbook.cellStore.sheetIds[cellIndex] ?? 0;
            if (sheetId === 0) {
                continue;
            }
            const position = args.state.workbook.getCellPosition(cellIndex);
            const row = position?.row ?? args.state.workbook.cellStore.rows[cellIndex] ?? 0;
            const col = position?.col ?? args.state.workbook.cellStore.cols[cellIndex] ?? 0;
            const isFormulaCell = (args.state.workbook.cellStore.formulaIds[cellIndex] ?? 0) !== 0;
            const rangeIndices = args.state.ranges.addDynamicMember(sheetId, row, col, cellIndex, isFormulaCell);
            if (rangeIndices.length > 0) {
                args.scheduleWasmProgramSync();
            }
            for (let rangeCursor = 0; rangeCursor < rangeIndices.length; rangeCursor += 1) {
                const rangeIndex = rangeIndices[rangeCursor];
                const rangeEntity = makeRangeEntity(rangeIndex);
                appendReverseEdge(makeCellEntity(cellIndex), rangeEntity);
                const formulas = getEntityDependents(rangeEntity);
                for (let formulaCursor = 0; formulaCursor < formulas.length; formulaCursor += 1) {
                    const formulaEntity = formulas[formulaCursor];
                    if (isRangeEntity(formulaEntity)) {
                        continue;
                    }
                    const formulaCellIndex = entityPayload(formulaEntity);
                    const formula = args.state.formulas.get(formulaCellIndex);
                    if (!formula) {
                        continue;
                    }
                    if (!isFormulaCell) {
                        continue;
                    }
                    const nextDependencyIndices = appendPackedCellIndex(formula.dependencyIndices, cellIndex);
                    if (nextDependencyIndices !== formula.dependencyIndices) {
                        formula.dependencyIndices = nextDependencyIndices;
                        formulaChangedCount = markFormulaChangedNow(formulaCellIndex, formulaChangedCount);
                    }
                }
            }
        }
        return formulaChangedCount;
    };
    return {
        beginMutationCollection() {
            return Effect.try({
                try: () => {
                    beginMutationCollectionNow();
                },
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to begin mutation collection', cause),
                    cause,
                }),
            });
        },
        markInputChanged(cellIndex, count) {
            return Effect.try({
                try: () => markInputChangedNow(cellIndex, count),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to mark input ${cellIndex} as changed`, cause),
                    cause,
                }),
            });
        },
        markFormulaChanged(cellIndex, count) {
            return Effect.try({
                try: () => markFormulaChangedNow(cellIndex, count),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to mark formula ${cellIndex} as changed`, cause),
                    cause,
                }),
            });
        },
        markVolatileFormulasChanged(count) {
            return Effect.try({
                try: () => markVolatileFormulasChangedNow(count),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to mark volatile formulas as changed', cause),
                    cause,
                }),
            });
        },
        markSpillRootsChanged(cellIndices, count) {
            return Effect.try({
                try: () => {
                    for (let index = 0; index < cellIndices.length; index += 1) {
                        count = markInputChangedNow(cellIndices[index], count);
                    }
                    return count;
                },
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to mark spill roots as changed', cause),
                    cause,
                }),
            });
        },
        markPivotRootsChanged(cellIndices, count) {
            return Effect.try({
                try: () => {
                    for (let index = 0; index < cellIndices.length; index += 1) {
                        count = markInputChangedNow(cellIndices[index], count);
                    }
                    return count;
                },
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to mark pivot roots as changed', cause),
                    cause,
                }),
            });
        },
        markExplicitChanged(cellIndex, count) {
            return Effect.try({
                try: () => markExplicitChangedNow(cellIndex, count),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to mark cell ${cellIndex} as explicit`, cause),
                    cause,
                }),
            });
        },
        composeMutationRoots(changedInputCount, formulaChangedCount) {
            return Effect.try({
                try: () => composeMutationRootsNow(changedInputCount, formulaChangedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to compose mutation roots', cause),
                    cause,
                }),
            });
        },
        composeEventChanges(recalculated, explicitChangedCount) {
            return Effect.try({
                try: () => composeEventChangesNow(recalculated, explicitChangedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to compose event changes', cause),
                    cause,
                }),
            });
        },
        composeDisjointEventChanges(recalculated, explicitChangedCount) {
            return Effect.try({
                try: () => composeDisjointEventChangesNow(recalculated, explicitChangedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to compose disjoint event changes', cause),
                    cause,
                }),
            });
        },
        unionChangedSets(...sets) {
            return Effect.try({
                try: () => unionChangedSetsNow(...sets),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to union changed sets', cause),
                    cause,
                }),
            });
        },
        composeChangedRootsAndOrdered(changedRoots, ordered, orderedCount) {
            return Effect.try({
                try: () => composeChangedRootsAndOrderedNow(changedRoots, ordered, orderedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to compose changed roots and order', cause),
                    cause,
                }),
            });
        },
        getChangedInputBuffer() {
            return Effect.try({
                try: () => args.getChangedInputBuffer(),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to read changed input buffer', cause),
                    cause,
                }),
            });
        },
        ensureCellTracked(sheetName, address) {
            return Effect.try({
                try: () => ensureCellTrackedNow(sheetName, address),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to ensure cell ${sheetName}!${address}`, cause),
                    cause,
                }),
            });
        },
        ensureCellTrackedByCoords(sheetId, row, col) {
            return Effect.try({
                try: () => ensureCellTrackedByCoordsNow(sheetId, row, col),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to ensure cell coordinates ${sheetId}:${row}:${col}`, cause),
                    cause,
                }),
            });
        },
        clearOwnedSpill(cellIndex) {
            return Effect.try({
                try: () => clearOwnedSpillNow(cellIndex),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to clear spill ${cellIndex}`, cause),
                    cause,
                }),
            });
        },
        clearSpillForCell(cellIndex) {
            return Effect.try({
                try: () => clearSpillForCellNow(cellIndex),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to clear spill containing ${cellIndex}`, cause),
                    cause,
                }),
            });
        },
        materializeSpill(cellIndex, arrayValue) {
            return Effect.try({
                try: () => materializeSpillNow(cellIndex, arrayValue),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to materialize spill ${cellIndex}`, cause),
                    cause,
                }),
            });
        },
        removeSheetRuntime(sheetName, explicitChangedCount) {
            return Effect.try({
                try: () => removeSheetRuntimeNow(sheetName, explicitChangedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to remove sheet runtime for ${sheetName}`, cause),
                    cause,
                }),
            });
        },
        syncDynamicRanges(formulaChangedCount) {
            return Effect.try({
                try: () => syncDynamicRangesNow(formulaChangedCount),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to sync dynamic ranges', cause),
                    cause,
                }),
            });
        },
        resetMaterializedCellScratch(expectedSize) {
            return Effect.try({
                try: () => resetMaterializedCellScratchNow(expectedSize),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage('Failed to reset materialized cell scratch', cause),
                    cause,
                }),
            });
        },
        beginMutationCollectionNow,
        markInputChangedNow,
        markFormulaChangedNow,
        markVolatileFormulasChangedNow,
        markSpillRootsChangedNow(cellIndices, count) {
            for (let index = 0; index < cellIndices.length; index += 1) {
                count = markInputChangedNow(cellIndices[index], count);
            }
            return count;
        },
        markPivotRootsChangedNow(cellIndices, count) {
            for (let index = 0; index < cellIndices.length; index += 1) {
                count = markInputChangedNow(cellIndices[index], count);
            }
            return count;
        },
        markExplicitChangedNow,
        composeMutationRootsNow,
        composeDisjointEventChangesNow,
        composeEventChangesNow,
        unionChangedSetsNow,
        composeChangedRootsAndOrderedNow,
        getChangedInputBufferNow,
        ensureCellTrackedNow,
        ensureCellTrackedByCoordsNow,
        clearOwnedSpillNow,
        clearSpillForCellNow,
        materializeSpillNow,
        removeSheetRuntimeNow,
        syncDynamicRangesNow,
        resetMaterializedCellScratchNow,
    };
}
//# sourceMappingURL=mutation-support-service.js.map