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, writeSingleInputAffineDirectScalar, } 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 createOperationDirectScalarSingleColumnBatchFastPaths(args) {
    const { emitBatch, hasTrackedExactLookupDependents, hasTrackedSortedLookupDependents, hasTrackedDirectRangeDependents, canFastPathLiteralOverwrite, canUseDirectFormulaPostRecalc, canSkipFormulaColumnVersion, applyTerminalDirectFormulaNumericResults, } = args;
    const tryApplyDenseSingleColumnDirectScalarLiteralBatch = (refs, batch, potentialNewCells) => {
        const firstRef = refs[0];
        if (firstRef === undefined || refs.length < 32 || (potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstMutation = firstRef.mutation;
        if (firstMutation.kind !== 'setCellValue' || typeof firstMutation.value !== 'number' || Object.is(firstMutation.value, -0)) {
            return false;
        }
        const secondMutation = refs[1]?.mutation;
        if (secondMutation?.kind !== 'setCellValue') {
            return false;
        }
        const rowOrder = secondMutation.row > firstMutation.row ? 1 : secondMutation.row < firstMutation.row ? -1 : 0;
        if (rowOrder === 0) {
            return false;
        }
        const firstSheet = args.state.workbook.getSheetById(firstRef.sheetId);
        if (!firstSheet ||
            firstSheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, firstMutation.col)) {
            return false;
        }
        const changedCellIndices = new Uint32Array(refs.length * 2);
        const inputCellIndices = changedCellIndices.subarray(0, refs.length);
        const formulaCellIndices = changedCellIndices.subarray(refs.length);
        const inputNumericValues = new Float64Array(refs.length);
        const formulaNumericResults = new Float64Array(refs.length);
        const cellStore = args.state.workbook.cellStore;
        const readDirectScalarNumber = (cellIndex) => directScalarCellNumber(cellStore, cellIndex);
        let previousRow = firstMutation.row;
        for (let refIndex = 0; refIndex < refs.length; refIndex += 1) {
            const ref = refs[refIndex];
            const mutation = ref.mutation;
            if (refIndex > 0) {
                if ((rowOrder > 0 && mutation.row <= previousRow) || (rowOrder < 0 && mutation.row >= previousRow)) {
                    return false;
                }
                previousRow = mutation.row;
            }
            if (ref.sheetId !== firstRef.sheetId ||
                mutation.kind !== 'setCellValue' ||
                mutation.col !== firstMutation.col ||
                typeof mutation.value !== 'number' ||
                Object.is(mutation.value, -0)) {
                return false;
            }
            const existingIndex = ref.cellIndex !== undefined &&
                args.state.workbook.cellStore.sheetIds[ref.cellIndex] === ref.sheetId &&
                args.state.workbook.cellStore.rows[ref.cellIndex] === mutation.row &&
                args.state.workbook.cellStore.cols[ref.cellIndex] === mutation.col
                ? ref.cellIndex
                : firstSheet.grid.getPhysical(mutation.row, mutation.col);
            if (existingIndex === -1 || !canFastPathLiteralOverwrite(existingIndex)) {
                return false;
            }
            const singleDependent = singleDirectScalarDependent(args, existingIndex);
            if (singleDependent < 0 || !canUseDirectFormulaPostRecalc(singleDependent) || !canSkipFormulaColumnVersion(singleDependent)) {
                return false;
            }
            const formula = args.state.formulas.get(singleDependent);
            const result = formula?.directScalar === undefined
                ? undefined
                : evaluateDirectScalarWithReplacementNumbers(formula.directScalar, existingIndex, mutation.value, readDirectScalarNumber);
            if (result === undefined) {
                return false;
            }
            const outputIndex = rowOrder < 0 ? refs.length - 1 - refIndex : refIndex;
            inputCellIndices[outputIndex] = existingIndex;
            formulaCellIndices[outputIndex] = singleDependent;
            inputNumericValues[outputIndex] = mutation.value;
            formulaNumericResults[outputIndex] = result;
        }
        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 formulaOutputFlags = 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */;
        const clearFormulaOutputFlags = ~formulaOutputFlags;
        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 & formulaOutputFlags) !== 0) {
                    flags[cellIndex] = currentFlags & clearFormulaOutputFlags;
                }
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
                stringIds[cellIndex] = 0;
                tags[cellIndex] = ValueTag.Number;
                numbers[cellIndex] = inputNumericValues[index];
                errors[cellIndex] = ErrorCode.None;
            }
            args.state.workbook.notifyColumnWritten(firstRef.sheetId, firstMutation.col);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        applyTerminalDirectFormulaNumericResults(formulaCellIndices, formulaNumericResults);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', refs.length);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? changedCellIndices : 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 tryApplyDenseSingleColumnAffineDirectScalarLiteralBatch = (refs, batch, potentialNewCells) => {
        const firstRef = refs[0];
        if (firstRef === undefined || refs.length < 32 || (potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstMutation = firstRef.mutation;
        if (firstMutation.kind !== 'setCellValue' || typeof firstMutation.value !== 'number' || Object.is(firstMutation.value, -0)) {
            return false;
        }
        const secondMutation = refs[1]?.mutation;
        if (secondMutation?.kind !== 'setCellValue') {
            return false;
        }
        const rowOrder = secondMutation.row > firstMutation.row ? 1 : secondMutation.row < firstMutation.row ? -1 : 0;
        if (rowOrder === 0) {
            return false;
        }
        const firstSheet = args.state.workbook.getSheetById(firstRef.sheetId);
        if (!firstSheet ||
            firstSheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedSortedLookupDependents(firstRef.sheetId, firstMutation.col) ||
            hasTrackedDirectRangeDependents(firstRef.sheetId, firstMutation.col)) {
            return false;
        }
        const hasGeneralEventListeners = args.state.events.hasListeners();
        const hasTrackedEventListeners = args.state.events.hasTrackedListeners();
        const hasWatchedCellListeners = args.state.events.hasCellListeners();
        if (!hasGeneralEventListeners && !hasTrackedEventListeners && !hasWatchedCellListeners) {
            return tryApplyDenseSingleColumnAffineDirectScalarLiteralBatchWithoutChangedSet(args, refs, batch, rowOrder);
        }
        const changedCellIndices = new Uint32Array(refs.length * 2);
        const inputCellIndices = changedCellIndices.subarray(0, refs.length);
        const inputNumericValues = rowOrder < 0 ? new Float64Array(refs.length) : undefined;
        const formulaCellIndices = changedCellIndices.subarray(refs.length);
        const cellStore = args.state.workbook.cellStore;
        let previousRow = firstMutation.row;
        let previousFormulaRow = -1;
        let previousFormulaCol = -1;
        let affineScale;
        let affineOffset;
        const affine = { scale: 0, offset: 0 };
        for (let refIndex = 0; refIndex < refs.length; refIndex += 1) {
            const ref = refs[refIndex];
            const mutation = ref.mutation;
            if (refIndex > 0) {
                if ((rowOrder > 0 && mutation.row <= previousRow) || (rowOrder < 0 && mutation.row >= previousRow)) {
                    return false;
                }
                previousRow = mutation.row;
            }
            if (ref.sheetId !== firstRef.sheetId ||
                mutation.kind !== 'setCellValue' ||
                mutation.col !== firstMutation.col ||
                typeof mutation.value !== 'number' ||
                Object.is(mutation.value, -0) ||
                ref.cellIndex === undefined ||
                cellStore.sheetIds[ref.cellIndex] !== ref.sheetId ||
                cellStore.rows[ref.cellIndex] !== mutation.row ||
                cellStore.cols[ref.cellIndex] !== mutation.col) {
                return false;
            }
            const existingIndex = ref.cellIndex;
            if (!canFastPathLiteralOverwrite(existingIndex)) {
                return false;
            }
            const singleDependent = singleDirectScalarDependent(args, existingIndex);
            if (singleDependent < 0 || !canUseDirectFormulaPostRecalc(singleDependent) || !canSkipFormulaColumnVersion(singleDependent)) {
                return false;
            }
            const formula = args.state.formulas.get(singleDependent);
            if (!formula ||
                formula.directScalar === undefined ||
                cellStore.sheetIds[singleDependent] !== firstRef.sheetId ||
                cellStore.rows[singleDependent] !== mutation.row) {
                return false;
            }
            const formulaRow = cellStore.rows[singleDependent] ?? 0;
            const formulaCol = cellStore.cols[singleDependent] ?? 0;
            if (refIndex > 0 &&
                ((rowOrder > 0 && (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol))) ||
                    (rowOrder < 0 && (formulaRow > previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol >= previousFormulaCol))))) {
                return false;
            }
            if (!writeSingleInputAffineDirectScalar(formula.directScalar, existingIndex, affine)) {
                return false;
            }
            if (affineScale === undefined) {
                affineScale = affine.scale;
                affineOffset = affine.offset;
            }
            else if (!Object.is(affineScale, affine.scale) || !Object.is(affineOffset, affine.offset)) {
                return false;
            }
            const outputIndex = rowOrder < 0 ? refs.length - 1 - refIndex : refIndex;
            inputCellIndices[outputIndex] = existingIndex;
            if (inputNumericValues !== undefined) {
                inputNumericValues[outputIndex] = mutation.value;
            }
            formulaCellIndices[outputIndex] = singleDependent;
            previousFormulaRow = formulaRow;
            previousFormulaCol = formulaCol;
        }
        if (affineScale === undefined || affineOffset === undefined) {
            return false;
        }
        args.materializeDeferredStructuralFormulaSources();
        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 formulaOutputFlags = 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */;
        const clearFormulaOutputFlags = ~formulaOutputFlags;
        args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
        try {
            for (let index = 0; index < refs.length; index += 1) {
                const cellIndex = inputCellIndices[index];
                const value = inputNumericValues === undefined ? readValidatedNumericMutationValue(refs[index]) : inputNumericValues[index];
                const inputFlags = flags[cellIndex] ?? 0;
                if ((inputFlags & formulaOutputFlags) !== 0) {
                    flags[cellIndex] = inputFlags & clearFormulaOutputFlags;
                }
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
                stringIds[cellIndex] = 0;
                tags[cellIndex] = ValueTag.Number;
                numbers[cellIndex] = value;
                errors[cellIndex] = ErrorCode.None;
                const formulaCellIndex = formulaCellIndices[index];
                const currentFlags = flags[formulaCellIndex] ?? 0;
                if ((currentFlags & formulaOutputFlags) !== 0) {
                    flags[formulaCellIndex] = currentFlags & clearFormulaOutputFlags;
                }
                versions[formulaCellIndex] = (versions[formulaCellIndex] ?? 0) + 1;
                stringIds[formulaCellIndex] = 0;
                tags[formulaCellIndex] = ValueTag.Number;
                numbers[formulaCellIndex] = value * affineScale + affineOffset;
                errors[formulaCellIndex] = ErrorCode.None;
            }
            args.state.workbook.notifyColumnWritten(firstRef.sheetId, firstMutation.col);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', refs.length);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? changedCellIndices : 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 tryApplyDenseSingleColumnAffineExistingNumericBatch = (record, batch) => {
        const count = record.sheetIds.length;
        if (count < 32 || (record.potentialNewCells ?? 0) !== 0) {
            return false;
        }
        const firstSheetId = record.sheetIds[0];
        const firstRow = record.rows[0];
        const firstCol = record.cols[0];
        const secondRow = record.rows[1];
        const rowOrder = secondRow > firstRow ? 1 : secondRow < firstRow ? -1 : 0;
        if (rowOrder === 0) {
            return false;
        }
        const firstSheet = args.state.workbook.getSheetById(firstSheetId);
        if (!firstSheet ||
            firstSheet.structureVersion !== 1 ||
            hasTrackedExactLookupDependents(firstSheetId, firstCol) ||
            hasTrackedSortedLookupDependents(firstSheetId, firstCol) ||
            hasTrackedDirectRangeDependents(firstSheetId, firstCol)) {
            return false;
        }
        const hasGeneralEventListeners = args.state.events.hasListeners();
        const hasTrackedEventListeners = args.state.events.hasTrackedListeners();
        const hasWatchedCellListeners = args.state.events.hasCellListeners();
        if (!hasGeneralEventListeners && !hasTrackedEventListeners && !hasWatchedCellListeners) {
            return tryApplyDenseSingleColumnAffineExistingNumericBatchWithoutChangedSet(args, record, batch, rowOrder);
        }
        const changedCellIndices = new Uint32Array(count * 2);
        const inputCellIndices = changedCellIndices.subarray(0, count);
        const inputNumericValues = rowOrder < 0 ? new Float64Array(count) : undefined;
        const formulaCellIndices = changedCellIndices.subarray(count);
        const cellStore = args.state.workbook.cellStore;
        let previousRow = firstRow;
        let previousFormulaRow = -1;
        let previousFormulaCol = -1;
        let affineScale;
        let affineOffset;
        const affine = { scale: 0, offset: 0 };
        for (let refIndex = 0; refIndex < count; refIndex += 1) {
            const row = record.rows[refIndex];
            const col = record.cols[refIndex];
            const sheetId = record.sheetIds[refIndex];
            const cellIndexPlusOne = record.cellIndexPlusOnes[refIndex];
            const value = record.numbers[refIndex];
            if (refIndex > 0) {
                if ((rowOrder > 0 && row <= previousRow) || (rowOrder < 0 && row >= previousRow)) {
                    return false;
                }
                previousRow = row;
            }
            if (sheetId !== firstSheetId || col !== firstCol || Object.is(value, -0) || cellIndexPlusOne === 0) {
                return false;
            }
            const existingIndex = cellIndexPlusOne - 1;
            if (cellStore.sheetIds[existingIndex] !== sheetId ||
                cellStore.rows[existingIndex] !== row ||
                cellStore.cols[existingIndex] !== col ||
                !canFastPathLiteralOverwrite(existingIndex)) {
                return false;
            }
            const singleDependent = singleDirectScalarDependent(args, existingIndex);
            if (singleDependent < 0 || !canUseDirectFormulaPostRecalc(singleDependent) || !canSkipFormulaColumnVersion(singleDependent)) {
                return false;
            }
            const formula = args.state.formulas.get(singleDependent);
            if (!formula ||
                formula.directScalar === undefined ||
                cellStore.sheetIds[singleDependent] !== firstSheetId ||
                cellStore.rows[singleDependent] !== row) {
                return false;
            }
            const formulaRow = cellStore.rows[singleDependent] ?? 0;
            const formulaCol = cellStore.cols[singleDependent] ?? 0;
            if (refIndex > 0 &&
                ((rowOrder > 0 && (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol))) ||
                    (rowOrder < 0 && (formulaRow > previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol >= previousFormulaCol))))) {
                return false;
            }
            if (!writeSingleInputAffineDirectScalar(formula.directScalar, existingIndex, affine)) {
                return false;
            }
            if (affineScale === undefined) {
                affineScale = affine.scale;
                affineOffset = affine.offset;
            }
            else if (!Object.is(affineScale, affine.scale) || !Object.is(affineOffset, affine.offset)) {
                return false;
            }
            const outputIndex = rowOrder < 0 ? count - 1 - refIndex : refIndex;
            inputCellIndices[outputIndex] = existingIndex;
            if (inputNumericValues !== undefined) {
                inputNumericValues[outputIndex] = value;
            }
            formulaCellIndices[outputIndex] = singleDependent;
            previousFormulaRow = formulaRow;
            previousFormulaCol = formulaCol;
        }
        if (affineScale === undefined || affineOffset === undefined) {
            return false;
        }
        args.materializeDeferredStructuralFormulaSources();
        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 formulaOutputFlags = 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */;
        const clearFormulaOutputFlags = ~formulaOutputFlags;
        args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
        try {
            for (let index = 0; index < count; index += 1) {
                const cellIndex = inputCellIndices[index];
                const value = inputNumericValues === undefined ? record.numbers[index] : inputNumericValues[index];
                const inputFlags = flags[cellIndex] ?? 0;
                if ((inputFlags & formulaOutputFlags) !== 0) {
                    flags[cellIndex] = inputFlags & clearFormulaOutputFlags;
                }
                versions[cellIndex] = (versions[cellIndex] ?? 0) + 1;
                stringIds[cellIndex] = 0;
                tags[cellIndex] = ValueTag.Number;
                numbers[cellIndex] = value;
                errors[cellIndex] = ErrorCode.None;
                const formulaCellIndex = formulaCellIndices[index];
                const currentFlags = flags[formulaCellIndex] ?? 0;
                if ((currentFlags & formulaOutputFlags) !== 0) {
                    flags[formulaCellIndex] = currentFlags & clearFormulaOutputFlags;
                }
                versions[formulaCellIndex] = (versions[formulaCellIndex] ?? 0) + 1;
                stringIds[formulaCellIndex] = 0;
                tags[formulaCellIndex] = ValueTag.Number;
                numbers[formulaCellIndex] = value * affineScale + affineOffset;
                errors[formulaCellIndex] = ErrorCode.None;
            }
            args.state.workbook.notifyColumnWritten(firstSheetId, firstCol);
        }
        finally {
            args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
        }
        if (batch) {
            markBatchApplied(args.state.replicaState, batch);
        }
        args.deferKernelSync(inputCellIndices);
        addEngineCounter(args.state.counters, 'directScalarDeltaApplications', count);
        addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
        const changed = requiresChangedSet ? changedCellIndices : 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;
    };
    return {
        tryApplyDenseSingleColumnAffineDirectScalarLiteralBatch,
        tryApplyDenseSingleColumnDirectScalarLiteralBatch,
        tryApplyDenseSingleColumnAffineExistingNumericBatch,
    };
}
function singleDirectScalarDependent(args, inputCellIndex) {
    const indexedDependent = args.state.directScalarDeltaOutputCellIndicesByInput[inputCellIndex];
    if (indexedDependent !== undefined) {
        if (indexedDependent < 0) {
            return indexedDependent;
        }
        const dependents = args.getEntityDependents(makeCellEntity(inputCellIndex));
        return dependents.length === 1 && dependents[0] === indexedDependent ? indexedDependent : -2;
    }
    const dependents = args.getEntityDependents(makeCellEntity(inputCellIndex));
    if (dependents.length === 0) {
        return -1;
    }
    return dependents.length === 1 ? dependents[0] : -2;
}
function tryApplyDenseSingleColumnAffineDirectScalarLiteralBatchWithoutChangedSet(args, refs, batch, rowOrder) {
    const firstRef = refs[0];
    const firstMutation = firstRef.mutation;
    if (firstMutation.kind !== 'setCellValue') {
        return false;
    }
    const inputCellIndices = new Uint32Array(refs.length);
    const formulaCellIndices = new Uint32Array(refs.length);
    const cellStore = args.state.workbook.cellStore;
    let previousRow = firstMutation.row;
    let previousFormulaRow = -1;
    let previousFormulaCol = -1;
    let affineScale;
    let affineOffset;
    const affine = { scale: 0, offset: 0 };
    for (let refIndex = 0; refIndex < refs.length; refIndex += 1) {
        const ref = refs[refIndex];
        const mutation = ref.mutation;
        if (refIndex > 0) {
            if ((rowOrder > 0 && mutation.row <= previousRow) || (rowOrder < 0 && mutation.row >= previousRow)) {
                return false;
            }
            previousRow = mutation.row;
        }
        if (ref.sheetId !== firstRef.sheetId ||
            mutation.kind !== 'setCellValue' ||
            mutation.col !== firstMutation.col ||
            typeof mutation.value !== 'number' ||
            Object.is(mutation.value, -0) ||
            ref.cellIndex === undefined ||
            cellStore.sheetIds[ref.cellIndex] !== ref.sheetId ||
            cellStore.rows[ref.cellIndex] !== mutation.row ||
            cellStore.cols[ref.cellIndex] !== mutation.col) {
            return false;
        }
        const existingIndex = ref.cellIndex;
        if (!args.canFastPathLiteralOverwrite(existingIndex)) {
            return false;
        }
        const formulaCellIndex = singleDirectScalarDependent(args, existingIndex);
        if (formulaCellIndex < 0 ||
            !args.canUseDirectFormulaPostRecalc(formulaCellIndex) ||
            !args.canSkipFormulaColumnVersion(formulaCellIndex)) {
            return false;
        }
        const formula = args.state.formulas.get(formulaCellIndex);
        if (!formula ||
            formula.directScalar === undefined ||
            cellStore.sheetIds[formulaCellIndex] !== firstRef.sheetId ||
            cellStore.rows[formulaCellIndex] !== mutation.row) {
            return false;
        }
        const formulaRow = cellStore.rows[formulaCellIndex] ?? 0;
        const formulaCol = cellStore.cols[formulaCellIndex] ?? 0;
        if (refIndex > 0 &&
            ((rowOrder > 0 && (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol))) ||
                (rowOrder < 0 && (formulaRow > previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol >= previousFormulaCol))))) {
            return false;
        }
        if (!writeSingleInputAffineDirectScalar(formula.directScalar, existingIndex, affine)) {
            return false;
        }
        if (affineScale === undefined) {
            affineScale = affine.scale;
            affineOffset = affine.offset;
        }
        else if (!Object.is(affineScale, affine.scale) || !Object.is(affineOffset, affine.offset)) {
            return false;
        }
        inputCellIndices[refIndex] = existingIndex;
        formulaCellIndices[refIndex] = formulaCellIndex;
        previousFormulaRow = formulaRow;
        previousFormulaCol = formulaCol;
    }
    if (affineScale === undefined || affineOffset === undefined) {
        return false;
    }
    args.materializeDeferredStructuralFormulaSources();
    writeValidatedAffineSingleColumnLiteralBatchWithoutChangedSet(args, refs, inputCellIndices, formulaCellIndices, firstRef.sheetId, firstMutation.col, affineScale, affineOffset);
    if (batch) {
        markBatchApplied(args.state.replicaState, batch);
    }
    args.deferKernelSync(inputCellIndices);
    addEngineCounter(args.state.counters, 'directScalarDeltaApplications', refs.length);
    addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
    emitCellMutationFastPathBatchResult({
        state: args.state,
        changed: EMPTY_CHANGED_CELLS,
        changedInputCount: refs.length,
        explicitChangedCount: 0,
        hasGeneralEventListeners: false,
        hasTrackedEventListeners: false,
        hasWatchedCellListeners: false,
        captureChangedCells: args.captureChangedCells,
        batch,
        emitBatch: args.emitBatch,
    });
    return true;
}
function tryApplyDenseSingleColumnAffineExistingNumericBatchWithoutChangedSet(args, record, batch, rowOrder) {
    const count = record.sheetIds.length;
    const firstSheetId = record.sheetIds[0];
    const firstRow = record.rows[0];
    const firstCol = record.cols[0];
    const inputCellIndices = new Uint32Array(count);
    const formulaCellIndices = new Uint32Array(count);
    const cellStore = args.state.workbook.cellStore;
    let previousRow = firstRow;
    let previousFormulaRow = -1;
    let previousFormulaCol = -1;
    let affineScale;
    let affineOffset;
    const affine = { scale: 0, offset: 0 };
    for (let refIndex = 0; refIndex < count; refIndex += 1) {
        const row = record.rows[refIndex];
        const col = record.cols[refIndex];
        const sheetId = record.sheetIds[refIndex];
        const cellIndexPlusOne = record.cellIndexPlusOnes[refIndex];
        const value = record.numbers[refIndex];
        if (refIndex > 0) {
            if ((rowOrder > 0 && row <= previousRow) || (rowOrder < 0 && row >= previousRow)) {
                return false;
            }
            previousRow = row;
        }
        if (sheetId !== firstSheetId || col !== firstCol || Object.is(value, -0) || cellIndexPlusOne === 0) {
            return false;
        }
        const existingIndex = cellIndexPlusOne - 1;
        if (cellStore.sheetIds[existingIndex] !== sheetId ||
            cellStore.rows[existingIndex] !== row ||
            cellStore.cols[existingIndex] !== col ||
            !args.canFastPathLiteralOverwrite(existingIndex)) {
            return false;
        }
        const formulaCellIndex = singleDirectScalarDependent(args, existingIndex);
        if (formulaCellIndex < 0 ||
            !args.canUseDirectFormulaPostRecalc(formulaCellIndex) ||
            !args.canSkipFormulaColumnVersion(formulaCellIndex)) {
            return false;
        }
        const formula = args.state.formulas.get(formulaCellIndex);
        if (!formula ||
            formula.directScalar === undefined ||
            cellStore.sheetIds[formulaCellIndex] !== firstSheetId ||
            cellStore.rows[formulaCellIndex] !== row) {
            return false;
        }
        const formulaRow = cellStore.rows[formulaCellIndex] ?? 0;
        const formulaCol = cellStore.cols[formulaCellIndex] ?? 0;
        if (refIndex > 0 &&
            ((rowOrder > 0 && (formulaRow < previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol <= previousFormulaCol))) ||
                (rowOrder < 0 && (formulaRow > previousFormulaRow || (formulaRow === previousFormulaRow && formulaCol >= previousFormulaCol))))) {
            return false;
        }
        if (!writeSingleInputAffineDirectScalar(formula.directScalar, existingIndex, affine)) {
            return false;
        }
        if (affineScale === undefined) {
            affineScale = affine.scale;
            affineOffset = affine.offset;
        }
        else if (!Object.is(affineScale, affine.scale) || !Object.is(affineOffset, affine.offset)) {
            return false;
        }
        inputCellIndices[refIndex] = existingIndex;
        formulaCellIndices[refIndex] = formulaCellIndex;
        previousFormulaRow = formulaRow;
        previousFormulaCol = formulaCol;
    }
    if (affineScale === undefined || affineOffset === undefined) {
        return false;
    }
    args.materializeDeferredStructuralFormulaSources();
    writeValidatedAffineSingleColumnExistingNumericBatchWithoutChangedSet(args, record, inputCellIndices, formulaCellIndices, firstSheetId, firstCol, affineScale, affineOffset);
    if (batch) {
        markBatchApplied(args.state.replicaState, batch);
    }
    args.deferKernelSync(inputCellIndices);
    addEngineCounter(args.state.counters, 'directScalarDeltaApplications', count);
    addEngineCounter(args.state.counters, 'directScalarDeltaOnlyRecalcSkips');
    emitCellMutationFastPathBatchResult({
        state: args.state,
        changed: EMPTY_CHANGED_CELLS,
        changedInputCount: count,
        explicitChangedCount: 0,
        hasGeneralEventListeners: false,
        hasTrackedEventListeners: false,
        hasWatchedCellListeners: false,
        captureChangedCells: args.captureChangedCells,
        batch,
        emitBatch: args.emitBatch,
    });
    return true;
}
function writeValidatedAffineSingleColumnLiteralBatchWithoutChangedSet(args, refs, inputCellIndices, formulaCellIndices, sheetId, col, affineScale, affineOffset) {
    const cellStore = args.state.workbook.cellStore;
    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 formulaOutputFlags = 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */;
    const clearFormulaOutputFlags = ~formulaOutputFlags;
    args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
    try {
        for (let index = 0; index < refs.length; index += 1) {
            const inputCellIndex = inputCellIndices[index];
            const value = readValidatedNumericMutationValue(refs[index]);
            writeValidatedAffineSingleColumnPair(inputCellIndex, formulaCellIndices[index], value, affineScale, affineOffset, flags, versions, stringIds, tags, numbers, errors, formulaOutputFlags, clearFormulaOutputFlags);
        }
        args.state.workbook.notifyColumnWritten(sheetId, col);
    }
    finally {
        args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
    }
}
function writeValidatedAffineSingleColumnExistingNumericBatchWithoutChangedSet(args, record, inputCellIndices, formulaCellIndices, sheetId, col, affineScale, affineOffset) {
    const cellStore = args.state.workbook.cellStore;
    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 formulaOutputFlags = 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */;
    const clearFormulaOutputFlags = ~formulaOutputFlags;
    args.setBatchMutationDepth(args.getBatchMutationDepth() + 1);
    try {
        for (let index = 0; index < inputCellIndices.length; index += 1) {
            writeValidatedAffineSingleColumnPair(inputCellIndices[index], formulaCellIndices[index], record.numbers[index], affineScale, affineOffset, flags, versions, stringIds, tags, numbers, errors, formulaOutputFlags, clearFormulaOutputFlags);
        }
        args.state.workbook.notifyColumnWritten(sheetId, col);
    }
    finally {
        args.setBatchMutationDepth(args.getBatchMutationDepth() - 1);
    }
}
function writeValidatedAffineSingleColumnPair(inputCellIndex, formulaCellIndex, value, affineScale, affineOffset, flags, versions, stringIds, tags, numbers, errors, formulaOutputFlags, clearFormulaOutputFlags) {
    const inputFlags = flags[inputCellIndex] ?? 0;
    if ((inputFlags & formulaOutputFlags) !== 0) {
        flags[inputCellIndex] = inputFlags & clearFormulaOutputFlags;
    }
    versions[inputCellIndex] = (versions[inputCellIndex] ?? 0) + 1;
    stringIds[inputCellIndex] = 0;
    tags[inputCellIndex] = ValueTag.Number;
    numbers[inputCellIndex] = value;
    errors[inputCellIndex] = ErrorCode.None;
    const formulaFlags = flags[formulaCellIndex] ?? 0;
    if ((formulaFlags & formulaOutputFlags) !== 0) {
        flags[formulaCellIndex] = formulaFlags & clearFormulaOutputFlags;
    }
    versions[formulaCellIndex] = (versions[formulaCellIndex] ?? 0) + 1;
    stringIds[formulaCellIndex] = 0;
    tags[formulaCellIndex] = ValueTag.Number;
    numbers[formulaCellIndex] = value * affineScale + affineOffset;
    errors[formulaCellIndex] = ErrorCode.None;
}
function readValidatedNumericMutationValue(ref) {
    const mutation = ref.mutation;
    if (mutation.kind !== 'setCellValue' || typeof mutation.value !== 'number') {
        throw new Error('Expected affine direct scalar batch to contain numeric literal writes');
    }
    return mutation.value;
}
//# sourceMappingURL=operation-direct-scalar-single-column-batch-fast-paths.js.map