import { ErrorCode, ValueTag } from '@bilig/protocol';
import { makeCellEntity } from '../../entity-ids.js';
import { addEngineCounter } from '../../perf/engine-counters.js';
import { markBatchApplied } from '../../replica-state.js';
import { directScalarCellNumber, evaluateDirectScalarWithReplacementNumbers, evaluateRowPairDirectScalarCode, rowPairDirectScalarCode, } from './direct-scalar-helpers.js';
import { tagTrustedPhysicalTrackedChanges } from './operation-change-helpers.js';
import { emitCellMutationFastPathBatchResult } from './operation-fast-path-batch-result.js';
const EMPTY_CHANGED_CELLS = new Uint32Array(0);
export function createOperationDirectScalarRowPairBatchFastPaths(args) {
    const { emitBatch, hasTrackedExactLookupDependents, hasTrackedSortedLookupDependents, hasTrackedDirectRangeDependents, canFastPathLiteralOverwrite, canUseDirectFormulaPostRecalc, canSkipFormulaColumnVersion, applyTerminalDirectFormulaNumericResults, } = args;
    const tryApplyDenseRowPairSimpleDirectScalarLiteralBatch = (refs, batch, potentialNewCells) => {
        if (refs.length < 32 || refs.length % 2 !== 0 || (potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstRef = refs[0];
        const secondRef = refs[1];
        const firstMutation = firstRef.mutation;
        const secondMutation = secondRef.mutation;
        if (firstMutation.kind !== 'setCellValue' ||
            secondMutation.kind !== 'setCellValue' ||
            firstRef.sheetId !== secondRef.sheetId ||
            firstMutation.row !== secondMutation.row ||
            firstMutation.col >= secondMutation.col ||
            typeof firstMutation.value !== 'number' ||
            typeof secondMutation.value !== 'number' ||
            Object.is(firstMutation.value, -0) ||
            Object.is(secondMutation.value, -0)) {
            return false;
        }
        const sheet = args.state.workbook.getSheetById(firstRef.sheetId);
        if (!sheet ||
            sheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedExactLookupDependents(firstRef.sheetId, secondMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, secondMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, secondMutation.col)) {
            return false;
        }
        const cellIndexBuffer = new Uint32Array(refs.length * 2);
        const inputCellIndices = cellIndexBuffer.subarray(0, refs.length);
        const formulaCellIndices = cellIndexBuffer.subarray(refs.length);
        const formulaNumericResults = new Float64Array(refs.length);
        const cellStore = args.state.workbook.cellStore;
        let formulaCount = 0;
        let previousRow = firstMutation.row - 1;
        let previousFormulaRow = -1;
        let previousFormulaCol = -1;
        for (let refIndex = 0; refIndex < refs.length; refIndex += 2) {
            const leftRef = refs[refIndex];
            const rightRef = refs[refIndex + 1];
            const leftMutation = leftRef.mutation;
            const rightMutation = rightRef.mutation;
            if (leftRef.sheetId !== firstRef.sheetId ||
                rightRef.sheetId !== firstRef.sheetId ||
                leftMutation.kind !== 'setCellValue' ||
                rightMutation.kind !== 'setCellValue' ||
                leftMutation.row !== rightMutation.row ||
                leftMutation.row <= previousRow ||
                leftMutation.col !== firstMutation.col ||
                rightMutation.col !== secondMutation.col ||
                typeof leftMutation.value !== 'number' ||
                typeof rightMutation.value !== 'number' ||
                Object.is(leftMutation.value, -0) ||
                Object.is(rightMutation.value, -0) ||
                leftRef.cellIndex === undefined ||
                rightRef.cellIndex === undefined ||
                cellStore.sheetIds[leftRef.cellIndex] !== leftRef.sheetId ||
                cellStore.rows[leftRef.cellIndex] !== leftMutation.row ||
                cellStore.cols[leftRef.cellIndex] !== leftMutation.col ||
                cellStore.sheetIds[rightRef.cellIndex] !== rightRef.sheetId ||
                cellStore.rows[rightRef.cellIndex] !== rightMutation.row ||
                cellStore.cols[rightRef.cellIndex] !== rightMutation.col) {
                return false;
            }
            previousRow = leftMutation.row;
            const leftValue = leftMutation.value;
            const rightValue = rightMutation.value;
            const leftIndex = leftRef.cellIndex;
            const rightIndex = rightRef.cellIndex;
            if (!canFastPathLiteralOverwrite(leftIndex) || !canFastPathLiteralOverwrite(rightIndex)) {
                return false;
            }
            const rowFormulaStart = formulaCount;
            const considerDependent = (formulaCellIndex) => {
                for (let index = rowFormulaStart; index < formulaCount; index += 1) {
                    if (formulaCellIndices[index] === formulaCellIndex) {
                        return true;
                    }
                }
                const formula = args.state.formulas.get(formulaCellIndex);
                if (!formula ||
                    formula.directScalar === undefined ||
                    cellStore.sheetIds[formulaCellIndex] !== firstRef.sheetId ||
                    cellStore.rows[formulaCellIndex] !== leftMutation.row ||
                    !canUseDirectFormulaPostRecalc(formulaCellIndex) ||
                    !canSkipFormulaColumnVersion(formulaCellIndex)) {
                    return false;
                }
                const formulaRow = cellStore.rows[formulaCellIndex] ?? 0;
                const formulaCol = cellStore.cols[formulaCellIndex] ?? 0;
                if (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol)) {
                    return false;
                }
                const code = rowPairDirectScalarCode(formula.directScalar, leftIndex, rightIndex);
                const result = code === 0 ? undefined : evaluateRowPairDirectScalarCode(code, leftValue, rightValue);
                if (result === undefined || formulaCount >= formulaCellIndices.length) {
                    return false;
                }
                formulaCellIndices[formulaCount] = formulaCellIndex;
                formulaNumericResults[formulaCount] = result;
                formulaCount += 1;
                previousFormulaRow = formulaRow;
                previousFormulaCol = formulaCol;
                return true;
            };
            const leftDependents = args.getEntityDependents(makeCellEntity(leftIndex));
            const rightDependents = args.getEntityDependents(makeCellEntity(rightIndex));
            if (leftDependents.length === 0 || rightDependents.length === 0) {
                return false;
            }
            for (let index = 0; index < leftDependents.length; index += 1) {
                if (!considerDependent(leftDependents[index])) {
                    return false;
                }
            }
            if (!sameDependentOrder(leftDependents, rightDependents)) {
                for (let index = 0; index < rightDependents.length; index += 1) {
                    if (!considerDependent(rightDependents[index])) {
                        return false;
                    }
                }
            }
            if (formulaCount !== rowFormulaStart + 2) {
                return false;
            }
            inputCellIndices[refIndex] = leftIndex;
            inputCellIndices[refIndex + 1] = rightIndex;
        }
        if (formulaCount !== refs.length) {
            return false;
        }
        args.materializeDeferredStructuralFormulaSources();
        const hasGeneralEventListeners = args.state.events.hasListeners();
        const hasTrackedEventListeners = args.state.events.hasTrackedListeners();
        const hasWatchedCellListeners = args.state.events.hasCellListeners();
        const requiresChangedSet = hasGeneralEventListeners || hasTrackedEventListeners || hasWatchedCellListeners;
        const changedInputCount = inputCellIndices.length;
        const explicitChangedCount = requiresChangedSet ? inputCellIndices.length : 0;
        const flags = cellStore.flags;
        const versions = cellStore.versions;
        const stringIds = cellStore.stringIds;
        const tags = cellStore.tags;
        const numbers = cellStore.numbers;
        const errors = cellStore.errors;
        const clearAuthoredBlankFlag = ~256 /* CellFlags.AuthoredBlank */;
        args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
        try {
            for (let index = 0; index < refs.length; index += 1) {
                const ref = refs[index];
                const cellIndex = ref.cellIndex;
                const mutation = ref.mutation;
                if (mutation.kind !== 'setCellValue' || typeof mutation.value !== 'number') {
                    throw new Error('Expected dense row-pair batch to contain only numeric literal writes');
                }
                const currentFlags = flags[cellIndex] ?? 0;
                if ((currentFlags & 256 /* CellFlags.AuthoredBlank */) !== 0) {
                    flags[cellIndex] = currentFlags & clearAuthoredBlankFlag;
                }
                tags[cellIndex] = ValueTag.Number;
                errors[cellIndex] = ErrorCode.None;
                stringIds[cellIndex] = 0;
                numbers[cellIndex] = mutation.value;
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
            }
            args.state.workbook.notifyColumnPairWritten(firstRef.sheetId, firstMutation.col, secondMutation.col);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        applyTerminalDirectFormulaNumericResults(formulaCellIndices, formulaNumericResults, formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? composeDenseInputFormulaChanges(inputCellIndices, formulaCellIndices) : EMPTY_CHANGED_CELLS;
        if (hasTrackedEventListeners && changed.length > 4 && explicitChangedCount > 0 && explicitChangedCount < changed.length) {
            tagTrustedPhysicalTrackedChanges(changed, firstRef.sheetId, explicitChangedCount);
        }
        emitCellMutationFastPathBatchResult({
            state: args.state,
            changed,
            changedInputCount,
            explicitChangedCount,
            hasGeneralEventListeners,
            hasTrackedEventListeners,
            hasWatchedCellListeners,
            captureChangedCells: args.captureChangedCells,
            batch,
            emitBatch,
        });
        return true;
    };
    const tryApplyDenseRowPairExistingNumericBatch = (record, batch) => {
        const count = record.sheetIds.length;
        if (count < 32 || count % 2 !== 0 || (record.potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstSheetId = record.sheetIds[0];
        const firstRow = record.rows[0];
        const firstCol = record.cols[0];
        const secondSheetId = record.sheetIds[1];
        const secondRow = record.rows[1];
        const secondCol = record.cols[1];
        if (firstSheetId !== secondSheetId || firstRow !== secondRow || firstCol >= secondCol) {
            return false;
        }
        const sheet = args.state.workbook.getSheetById(firstSheetId);
        if (!sheet ||
            sheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstSheetId, firstCol) ||
            hasTrackedExactLookupDependents(firstSheetId, secondCol) ||
            hasTrackedSortedLookupDependents(firstSheetId, firstCol) ||
            hasTrackedSortedLookupDependents(firstSheetId, secondCol) ||
            hasTrackedDirectRangeDependents(firstSheetId, firstCol) ||
            hasTrackedDirectRangeDependents(firstSheetId, secondCol)) {
            return false;
        }
        const cellIndexBuffer = new Uint32Array(count * 2);
        const inputCellIndices = cellIndexBuffer.subarray(0, count);
        const formulaCellIndices = cellIndexBuffer.subarray(count, count * 2);
        const formulaNumericResults = new Float64Array(count);
        const cellStore = args.state.workbook.cellStore;
        let formulaCount = 0;
        let previousRow = firstRow - 1;
        let previousFormulaRow = -1;
        let previousFormulaCol = -1;
        for (let refIndex = 0; refIndex < count; refIndex += 2) {
            const leftSheetId = record.sheetIds[refIndex];
            const rightSheetId = record.sheetIds[refIndex + 1];
            const leftRow = record.rows[refIndex];
            const rightRow = record.rows[refIndex + 1];
            const leftCol = record.cols[refIndex];
            const rightCol = record.cols[refIndex + 1];
            const leftValue = record.numbers[refIndex];
            const rightValue = record.numbers[refIndex + 1];
            const leftCellIndexPlusOne = record.cellIndexPlusOnes[refIndex];
            const rightCellIndexPlusOne = record.cellIndexPlusOnes[refIndex + 1];
            if (leftSheetId !== firstSheetId ||
                rightSheetId !== firstSheetId ||
                leftRow !== rightRow ||
                leftRow <= previousRow ||
                leftCol !== firstCol ||
                rightCol !== secondCol ||
                Object.is(leftValue, -0) ||
                Object.is(rightValue, -0) ||
                leftCellIndexPlusOne === 0 ||
                rightCellIndexPlusOne === 0) {
                return false;
            }
            previousRow = leftRow;
            const leftIndex = leftCellIndexPlusOne - 1;
            const rightIndex = rightCellIndexPlusOne - 1;
            if (cellStore.sheetIds[leftIndex] !== leftSheetId ||
                cellStore.rows[leftIndex] !== leftRow ||
                cellStore.cols[leftIndex] !== leftCol ||
                cellStore.sheetIds[rightIndex] !== rightSheetId ||
                cellStore.rows[rightIndex] !== rightRow ||
                cellStore.cols[rightIndex] !== rightCol ||
                !canFastPathLiteralOverwrite(leftIndex) ||
                !canFastPathLiteralOverwrite(rightIndex)) {
                return false;
            }
            const rowFormulaStart = formulaCount;
            const considerDependent = (formulaCellIndex) => {
                for (let index = rowFormulaStart; index < formulaCount; index += 1) {
                    if (formulaCellIndices[index] === formulaCellIndex) {
                        return true;
                    }
                }
                const formula = args.state.formulas.get(formulaCellIndex);
                if (!formula ||
                    formula.directScalar === undefined ||
                    cellStore.sheetIds[formulaCellIndex] !== firstSheetId ||
                    cellStore.rows[formulaCellIndex] !== leftRow ||
                    !canUseDirectFormulaPostRecalc(formulaCellIndex) ||
                    !canSkipFormulaColumnVersion(formulaCellIndex)) {
                    return false;
                }
                const formulaRow = cellStore.rows[formulaCellIndex] ?? 0;
                const formulaCol = cellStore.cols[formulaCellIndex] ?? 0;
                if (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol)) {
                    return false;
                }
                const code = rowPairDirectScalarCode(formula.directScalar, leftIndex, rightIndex);
                const result = code === 0 ? undefined : evaluateRowPairDirectScalarCode(code, leftValue, rightValue);
                if (result === undefined || formulaCount >= formulaCellIndices.length) {
                    return false;
                }
                formulaCellIndices[formulaCount] = formulaCellIndex;
                formulaNumericResults[formulaCount] = result;
                formulaCount += 1;
                previousFormulaRow = formulaRow;
                previousFormulaCol = formulaCol;
                return true;
            };
            const leftDependents = args.getEntityDependents(makeCellEntity(leftIndex));
            const rightDependents = args.getEntityDependents(makeCellEntity(rightIndex));
            if (leftDependents.length === 0 || rightDependents.length === 0) {
                return false;
            }
            for (let index = 0; index < leftDependents.length; index += 1) {
                if (!considerDependent(leftDependents[index])) {
                    return false;
                }
            }
            if (!sameDependentOrder(leftDependents, rightDependents)) {
                for (let index = 0; index < rightDependents.length; index += 1) {
                    if (!considerDependent(rightDependents[index])) {
                        return false;
                    }
                }
            }
            if (formulaCount !== rowFormulaStart + 2) {
                return false;
            }
            inputCellIndices[refIndex] = leftIndex;
            inputCellIndices[refIndex + 1] = rightIndex;
        }
        if (formulaCount !== count) {
            return false;
        }
        args.materializeDeferredStructuralFormulaSources();
        const hasGeneralEventListeners = args.state.events.hasListeners();
        const hasTrackedEventListeners = args.state.events.hasTrackedListeners();
        const hasWatchedCellListeners = args.state.events.hasCellListeners();
        const requiresChangedSet = hasGeneralEventListeners || hasTrackedEventListeners || hasWatchedCellListeners;
        const changedInputCount = inputCellIndices.length;
        const explicitChangedCount = requiresChangedSet ? inputCellIndices.length : 0;
        const flags = cellStore.flags;
        const versions = cellStore.versions;
        const stringIds = cellStore.stringIds;
        const tags = cellStore.tags;
        const numbers = cellStore.numbers;
        const errors = cellStore.errors;
        const clearAuthoredBlankFlag = ~256 /* CellFlags.AuthoredBlank */;
        args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
        try {
            for (let index = 0; index < count; index += 1) {
                const cellIndex = inputCellIndices[index];
                const currentFlags = flags[cellIndex] ?? 0;
                if ((currentFlags & 256 /* CellFlags.AuthoredBlank */) !== 0) {
                    flags[cellIndex] = currentFlags & clearAuthoredBlankFlag;
                }
                tags[cellIndex] = ValueTag.Number;
                errors[cellIndex] = ErrorCode.None;
                stringIds[cellIndex] = 0;
                numbers[cellIndex] = record.numbers[index];
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
            }
            args.state.workbook.notifyColumnPairWritten(firstSheetId, firstCol, secondCol);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        applyTerminalDirectFormulaNumericResults(formulaCellIndices, formulaNumericResults, formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? composeDenseInputFormulaChanges(inputCellIndices, formulaCellIndices) : EMPTY_CHANGED_CELLS;
        if (hasTrackedEventListeners && changed.length > 4 && explicitChangedCount > 0 && explicitChangedCount < changed.length) {
            tagTrustedPhysicalTrackedChanges(changed, firstSheetId, explicitChangedCount);
        }
        emitCellMutationFastPathBatchResult({
            state: args.state,
            changed,
            changedInputCount,
            explicitChangedCount,
            hasGeneralEventListeners,
            hasTrackedEventListeners,
            hasWatchedCellListeners,
            captureChangedCells: args.captureChangedCells,
            batch,
            emitBatch,
        });
        return true;
    };
    const tryApplyDenseRowPairDirectScalarLiteralBatch = (refs, batch, potentialNewCells) => {
        if (refs.length < 32 || refs.length % 2 !== 0 || (potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstRef = refs[0];
        const secondRef = refs[1];
        const firstMutation = firstRef.mutation;
        const secondMutation = secondRef.mutation;
        if (firstMutation.kind !== 'setCellValue' ||
            secondMutation.kind !== 'setCellValue' ||
            firstRef.sheetId !== secondRef.sheetId ||
            firstMutation.row !== secondMutation.row ||
            firstMutation.col >= secondMutation.col ||
            typeof firstMutation.value !== 'number' ||
            typeof secondMutation.value !== 'number' ||
            Object.is(firstMutation.value, -0) ||
            Object.is(secondMutation.value, -0)) {
            return false;
        }
        const sheet = args.state.workbook.getSheetById(firstRef.sheetId);
        if (!sheet ||
            sheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedExactLookupDependents(firstRef.sheetId, secondMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, secondMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, secondMutation.col)) {
            return false;
        }
        const cellIndexBuffer = new Uint32Array(refs.length * 3);
        const inputCellIndices = cellIndexBuffer.subarray(0, refs.length);
        const inputNumericValues = new Float64Array(refs.length);
        const formulaCellIndices = cellIndexBuffer.subarray(refs.length);
        const formulaNumericResults = new Float64Array(refs.length * 2);
        const cellStore = args.state.workbook.cellStore;
        let formulaCount = 0;
        let previousRow = firstMutation.row - 1;
        let previousFormulaRow = -1;
        let previousFormulaCol = -1;
        const readDirectScalarNumber = (cellIndex) => directScalarCellNumber(cellStore, cellIndex);
        for (let refIndex = 0; refIndex < refs.length; refIndex += 2) {
            const leftRef = refs[refIndex];
            const rightRef = refs[refIndex + 1];
            const leftMutation = leftRef.mutation;
            const rightMutation = rightRef.mutation;
            if (leftRef.sheetId !== firstRef.sheetId ||
                rightRef.sheetId !== firstRef.sheetId ||
                leftMutation.kind !== 'setCellValue' ||
                rightMutation.kind !== 'setCellValue' ||
                leftMutation.row !== rightMutation.row ||
                leftMutation.row <= previousRow ||
                leftMutation.col !== firstMutation.col ||
                rightMutation.col !== secondMutation.col ||
                typeof leftMutation.value !== 'number' ||
                typeof rightMutation.value !== 'number' ||
                Object.is(leftMutation.value, -0) ||
                Object.is(rightMutation.value, -0)) {
                return false;
            }
            const leftValue = leftMutation.value;
            const rightValue = rightMutation.value;
            previousRow = leftMutation.row;
            const leftIndex = leftRef.cellIndex !== undefined &&
                cellStore.sheetIds[leftRef.cellIndex] === leftRef.sheetId &&
                cellStore.rows[leftRef.cellIndex] === leftMutation.row &&
                cellStore.cols[leftRef.cellIndex] === leftMutation.col
                ? leftRef.cellIndex
                : sheet.grid.getPhysical(leftMutation.row, leftMutation.col);
            const rightIndex = rightRef.cellIndex !== undefined &&
                cellStore.sheetIds[rightRef.cellIndex] === rightRef.sheetId &&
                cellStore.rows[rightRef.cellIndex] === rightMutation.row &&
                cellStore.cols[rightRef.cellIndex] === rightMutation.col
                ? rightRef.cellIndex
                : sheet.grid.getPhysical(rightMutation.row, rightMutation.col);
            if (leftIndex === -1 || rightIndex === -1 || !canFastPathLiteralOverwrite(leftIndex) || !canFastPathLiteralOverwrite(rightIndex)) {
                return false;
            }
            const rowFormulaStart = formulaCount;
            const considerDependent = (formulaCellIndex) => {
                for (let index = rowFormulaStart; index < formulaCount; index += 1) {
                    if (formulaCellIndices[index] === formulaCellIndex) {
                        return true;
                    }
                }
                const formula = args.state.formulas.get(formulaCellIndex);
                if (!formula ||
                    formula.directScalar === undefined ||
                    cellStore.sheetIds[formulaCellIndex] !== firstRef.sheetId ||
                    cellStore.rows[formulaCellIndex] !== leftMutation.row ||
                    !canUseDirectFormulaPostRecalc(formulaCellIndex) ||
                    !canSkipFormulaColumnVersion(formulaCellIndex)) {
                    return false;
                }
                const formulaRow = cellStore.rows[formulaCellIndex] ?? 0;
                const formulaCol = cellStore.cols[formulaCellIndex] ?? 0;
                if (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol)) {
                    return false;
                }
                const result = evaluateDirectScalarWithReplacementNumbers(formula.directScalar, leftIndex, leftValue, readDirectScalarNumber, rightIndex, rightValue);
                if (result === undefined || formulaCount >= formulaCellIndices.length) {
                    return false;
                }
                formulaCellIndices[formulaCount] = formulaCellIndex;
                formulaNumericResults[formulaCount] = result;
                formulaCount += 1;
                previousFormulaRow = formulaRow;
                previousFormulaCol = formulaCol;
                return true;
            };
            const leftDependents = args.getEntityDependents(makeCellEntity(leftIndex));
            const rightDependents = args.getEntityDependents(makeCellEntity(rightIndex));
            if (leftDependents.length === 0 || rightDependents.length === 0) {
                return false;
            }
            for (let index = 0; index < leftDependents.length; index += 1) {
                if (!considerDependent(leftDependents[index])) {
                    return false;
                }
            }
            if (!sameDependentOrder(leftDependents, rightDependents)) {
                for (let index = 0; index < rightDependents.length; index += 1) {
                    if (!considerDependent(rightDependents[index])) {
                        return false;
                    }
                }
            }
            inputCellIndices[refIndex] = leftIndex;
            inputCellIndices[refIndex + 1] = rightIndex;
            inputNumericValues[refIndex] = leftValue;
            inputNumericValues[refIndex + 1] = rightValue;
        }
        if (formulaCount === 0) {
            return false;
        }
        args.materializeDeferredStructuralFormulaSources();
        const hasGeneralEventListeners = args.state.events.hasListeners();
        const hasTrackedEventListeners = args.state.events.hasTrackedListeners();
        const hasWatchedCellListeners = args.state.events.hasCellListeners();
        const requiresChangedSet = hasGeneralEventListeners || hasTrackedEventListeners || hasWatchedCellListeners;
        const changedInputCount = inputCellIndices.length;
        const explicitChangedCount = requiresChangedSet ? inputCellIndices.length : 0;
        const flags = cellStore.flags;
        const versions = cellStore.versions;
        const stringIds = cellStore.stringIds;
        const tags = cellStore.tags;
        const numbers = cellStore.numbers;
        const errors = cellStore.errors;
        const clearAuthoredBlankFlag = ~256 /* CellFlags.AuthoredBlank */;
        args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
        try {
            for (let index = 0; index < refs.length; index += 1) {
                const cellIndex = inputCellIndices[index];
                const currentFlags = flags[cellIndex] ?? 0;
                if ((currentFlags & 256 /* CellFlags.AuthoredBlank */) !== 0) {
                    flags[cellIndex] = currentFlags & clearAuthoredBlankFlag;
                }
                tags[cellIndex] = ValueTag.Number;
                errors[cellIndex] = ErrorCode.None;
                stringIds[cellIndex] = 0;
                numbers[cellIndex] = inputNumericValues[index];
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
            }
            args.state.workbook.notifyColumnPairWritten(firstRef.sheetId, firstMutation.col, secondMutation.col);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        const formulaChanged = requiresChangedSet ? new Uint32Array(formulaCount) : EMPTY_CHANGED_CELLS;
        for (let index = 0; index < formulaCount; index += 1) {
            if (requiresChangedSet) {
                formulaChanged[index] = formulaCellIndices[index];
            }
        }
        applyTerminalDirectFormulaNumericResults(formulaCellIndices, formulaNumericResults, formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', formulaCount);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? composeDenseInputFormulaChanges(inputCellIndices, formulaChanged) : EMPTY_CHANGED_CELLS;
        if (hasTrackedEventListeners && changed.length > 4 && explicitChangedCount > 0 && explicitChangedCount < changed.length) {
            tagTrustedPhysicalTrackedChanges(changed, firstRef.sheetId, explicitChangedCount);
        }
        emitCellMutationFastPathBatchResult({
            state: args.state,
            changed,
            changedInputCount,
            explicitChangedCount,
            hasGeneralEventListeners,
            hasTrackedEventListeners,
            hasWatchedCellListeners,
            captureChangedCells: args.captureChangedCells,
            batch,
            emitBatch,
        });
        return true;
    };
    return {
        tryApplyDenseRowPairSimpleDirectScalarLiteralBatch,
        tryApplyDenseRowPairDirectScalarLiteralBatch,
        tryApplyDenseRowPairExistingNumericBatch,
    };
}
function composeDenseInputFormulaChanges(inputCellIndices, formulaCellIndices) {
    const changed = new Uint32Array(inputCellIndices.length + formulaCellIndices.length);
    changed.set(inputCellIndices);
    changed.set(formulaCellIndices, inputCellIndices.length);
    return changed;
}
function sameDependentOrder(left, right) {
    if (left === right) {
        return true;
    }
    if (left.length !== right.length) {
        return false;
    }
    for (let index = 0; index < left.length; index += 1) {
        if (left[index] !== right[index]) {
            return false;
        }
    }
    return true;
}
//# sourceMappingURL=operation-direct-scalar-row-pair-batch-fast-paths.js.map