import { Effect } from 'effect';
import { EngineMutationError } from '../errors.js';
import { hasOperationCycleMembers, markOperationCycleMemberInputsChanged, normalizeOperationHistoryDependencyPlaceholder, collectOperationDynamicFormulaDependents, pruneOperationCellIfOrphaned, refreshDependentRangesAndRebindOperationFormulaDependents, rebindOperationDynamicFormulaDependents, } from './operation-cell-lifecycle-helpers.js';
import { lookupImpactCacheKey } from './direct-formula-recalc-helpers.js';
import { mutationErrorMessage } from './operation-change-helpers.js';
import { createOperationReplicaVersionWriter } from './operation-replica-helpers.js';
import { createOperationDirectFormulaDeltas } from './operation-direct-formula-deltas.js';
import { createOperationDirectFormulaValues } from './operation-direct-formula-values.js';
import { createOperationDirectRangeDependentService } from './operation-direct-range-dependents.js';
import { createOperationDirectLookupCurrentService } from './operation-direct-lookup-current.js';
import { createOperationColumnDependencyTrackerService } from './operation-column-dependency-tracker.js';
import { createOperationLookupDirtyMarkerService } from './operation-lookup-dirty-markers.js';
import { createOperationDirectPostRecalcMarkers } from './operation-direct-post-recalc-markers.js';
import { createOperationDerivedOpApplier } from './operation-derived-op-helpers.js';
import { canSkipOperationDirtyTraversalForChangedInputs } from './operation-dirty-traversal-helpers.js';
import { countOperationPostRecalcDirectFormulaMetric } from './operation-post-recalc-direct-formulas.js';
import { tryApplySingleDirectAggregateLiteralMutationFastPath as tryApplySingleDirectAggregateLiteralMutationFastPathWithArgs, tryApplyTrustedColumnDirectAggregateExistingNumericMutation as tryApplyTrustedColumnDirectAggregateExistingNumericMutationWithArgs, tryApplyTrustedSingleRangeDirectAggregateExistingNumericMutation as tryApplyTrustedSingleRangeDirectAggregateExistingNumericMutationWithArgs, } from './operation-direct-aggregate-literal-fast-path.js';
import { tryApplyTrustedDirectScalarClosureExistingNumericMutation as tryApplyTrustedDirectScalarClosureExistingNumericMutationWithArgs } from './operation-direct-scalar-closure-fast-path.js';
import { tryApplyFormulaLeafExistingLiteralMutation as tryApplyFormulaLeafExistingLiteralMutationWithArgs, tryApplyTrustedFormulaLeafExistingNumericMutation as tryApplyTrustedFormulaLeafExistingNumericMutationWithArgs, } from './operation-formula-leaf-existing-numeric-fast-path.js';
import { createOperationDirectScalarBatchFastPaths } from './operation-direct-scalar-batch-fast-paths.js';
import { tryApplySingleDirectScalarLiteralMutationWithoutEvents as tryApplySingleDirectScalarLiteralMutationWithoutEventsWithArgs, tryApplySingleDirectScalarLiteralMutationWithoutEventsAndReturnChanged as tryApplySingleDirectScalarLiteralMutationWithoutEventsAndReturnChangedWithArgs, } from './operation-direct-scalar-literal-fast-path.js';
import { tryApplySingleDirectFormulaLiteralMutationWithoutEvents as tryApplySingleDirectFormulaLiteralMutationWithoutEventsWithArgs } from './operation-direct-formula-literal-fast-path.js';
import { createOperationSingleExistingLiteralFastPath } from './operation-single-existing-literal-fast-path.js';
import { createOperationLookupAccess } from './operation-lookup-access.js';
import { createOperationLookupPlanner } from './operation-lookup-planner.js';
import { tryApplySingleDirectLookupOperandMutationFastPath as tryApplySingleDirectLookupOperandMutationFastPathWithArgs } from './operation-direct-lookup-operand-fast-path.js';
import { canSkipOperationFormulaColumnVersion } from './operation-literal-write-helpers.js';
import { createOperationServiceRuntimeHelpers } from './operation-service-runtime-helpers.js';
import { tryApplyOperationFormulaReplacementAsDirectScalarDeltaRoot } from './operation-formula-replacement-direct-scalar.js';
import { tryApplySingleKernelSyncOnlyLiteralMutationFastPath as tryApplySingleKernelSyncOnlyLiteralMutationFastPathWithArgs } from './operation-kernel-sync-literal-fast-path.js';
import { createOperationBatchApplier } from './operation-batch-applier.js';
import { createOperationCellMutationApplier } from './operation-cell-mutation-applier.js';
import { ENGINE_OPERATION_TEST_HOOKS_ENABLED, } from './operation-service-types.js';
export { operationServiceTestHooks } from './operation-service-test-hooks.js';
const DIRECT_RANGE_POST_RECALC_LIMIT = 16_384;
const DIRECT_SCALAR_DELTA_CLOSURE_LIMIT = 4_096;
export function createEngineOperationService(args) {
    const { emitBatch, deferSingleCellKernelSync, makeSingleLiteralSkipMetrics, writeNumericLiteralToExistingCell, writeTrustedExistingNumericLiteralToCell, writeFastPathLiteralToExistingCell, cellsShareVersionColumn, withOptionalColumnVersionBatch, canFastPathLiteralOverwrite, isNullLiteralWriteNoOp, isClearCellNoOp, } = createOperationServiceRuntimeHelpers({
        state: args.state,
        deferKernelSync: args.deferKernelSync,
    });
    const replicaVersionWriter = createOperationReplicaVersionWriter({
        trackReplicaVersions: args.state.trackReplicaVersions,
        entityVersions: args.state.entityVersions,
        sheetDeleteVersions: args.state.sheetDeleteVersions,
    });
    const { setCellEntityVersion, setEntityVersionForOp } = replicaVersionWriter;
    const { readCellValueForLookup, readApproximateNumericValueForLookup, readExactNumericValueForLookup, readCellValueAtForLookup, readDirectCriteriaOperandValue, directCriteriaMatchesChangedAggregateRow, tryDirectCriteriaSumDelta, readApproximateNumericValueAtForLookup, isLocallySortedNumericWrite, isLocallySortedTextWrite, } = createOperationLookupAccess({
        workbook: args.state.workbook,
        strings: args.state.strings,
    });
    const { planSingleExactLookupNumericColumnWrite, planExactLookupNumericColumnWrite, canSkipExactLookupNumericColumnWrite, planSingleApproximateLookupNumericColumnWrite, planApproximateLookupNumericColumnWrite, canSkipApproximateLookupNumericColumnWrite, canSkipApproximateLookupNewNumericColumnWrite, canPatchUniformLookupTailWrite, patchUniformLookupTailWrites, canSkipApproximateLookupDirtyMark, } = createOperationLookupPlanner({
        state: args.state,
        access: {
            readExactNumericValueForLookup,
            readApproximateNumericValueForLookup,
            readCellValueForLookup,
            isLocallySortedNumericWrite,
            isLocallySortedTextWrite,
        },
        getSingleEntityDependent: args.getSingleEntityDependent,
        getEntityDependents: args.getEntityDependents,
    });
    const { markAffectedApproximateLookupDependents, noteExactLookupLiteralWriteWhenDirty, noteSortedLookupLiteralWriteWhenDirty } = createOperationLookupDirtyMarkerService({
        state: args.state,
        getEntityDependents: args.getEntityDependents,
        getSingleEntityDependent: args.getSingleEntityDependent,
        markFormulaChanged: args.markFormulaChanged,
        readCellValueForLookup,
        canSkipApproximateLookupDirtyMark,
        noteExactLookupLiteralWrite: args.noteExactLookupLiteralWrite,
        noteSortedLookupLiteralWrite: args.noteSortedLookupLiteralWrite,
        lookupImpactCacheKey,
    });
    const pruneCellIfOrphaned = (cellIndex) => {
        pruneOperationCellIfOrphaned({
            workbook: args.state.workbook,
            cellIndex,
            collectFormulaDependents: args.collectFormulaDependents,
        });
    };
    const normalizeHistoryDependencyPlaceholder = (cellIndex, source) => {
        normalizeOperationHistoryDependencyPlaceholder({
            state: args.state,
            source,
            cellIndex,
            collectFormulaDependents: args.collectFormulaDependents,
        });
    };
    const markCycleMemberInputsChanged = (changedInputCount) => {
        return markOperationCycleMemberInputsChanged({
            formulas: args.state.formulas,
            cellStore: args.state.workbook.cellStore,
            changedInputCount,
            markInputChanged: args.markInputChanged,
        });
    };
    const hasCycleMembersNow = () => {
        return hasOperationCycleMembers({
            counters: args.state.counters,
            formulas: args.state.formulas,
            cellStore: args.state.workbook.cellStore,
        });
    };
    const rebindDynamicFormulaDependents = (cellIndex, formulaChangedCount) => rebindOperationDynamicFormulaDependents({
        cellIndex,
        formulaChangedCount,
        formulas: args.state.formulas,
        collectFormulaDependents: args.collectFormulaDependents,
        rebindFormulaCells: args.rebindFormulaCells,
    });
    const hasDynamicFormulaDependents = (cellIndex) => collectOperationDynamicFormulaDependents({
        cellIndex,
        formulas: args.state.formulas,
        collectFormulaDependents: args.collectFormulaDependents,
    }).length > 0;
    const { readDirectScalarCellNumber, directScalarCellNumericValue, directScalarCurrentResultMatchesCell, directScalarNumericResultMatchesCell, applyDirectFormulaCurrentResult, applyDirectFormulaNumericResult, applyTerminalDirectFormulaNumericResult, applyTerminalDirectFormulaNumericResults, applyTerminalDirectFormulaAffineNumericResults, applyTerminalDirectFormulaAffineNumericResultsFromRefs, writeNumericLiteralToCellStore, evaluateDirectScalarCurrentValue, applyDirectScalarCurrentValue, tryEvaluateDirectScalarWithPendingNumbers, tryEvaluateDirectScalarNumericWithPendingNumbers, } = createOperationDirectFormulaValues({
        state: args.state,
    });
    const { tryDirectUniformLookupCurrentResult, tryDirectUniformLookupCurrentResultFromNumeric, tryDirectUniformLookupNumericResultFromDescriptor, canEvaluateDirectUniformLookupCurrentResultFromNumeric, tryDirectApproximateLookupCurrentResultFromNumeric, tryDirectExactLookupCurrentResult, } = createOperationDirectLookupCurrentService({
        state: args.state,
        exactLookup: args.exactLookup,
        sortedLookup: args.sortedLookup,
    });
    const { hasTrackedExactLookupDependents, hasTrackedSortedLookupDependents, hasTrackedDirectRangeDependents, hasTrackedColumnDependents, hasTrackedColumnDependentsAnywhere, hasNoCellDependents, } = createOperationColumnDependencyTrackerService({
        reverseState: args.reverseState,
        workbook: args.state.workbook,
        hasRegionFormulaSubscriptionsForColumn: args.hasRegionFormulaSubscriptionsForColumn,
        hasRegionFormulaSubscriptionsForColumnAt: args.hasRegionFormulaSubscriptionsForColumnAt,
        hasRegionFormulaSubscriptions: args.hasRegionFormulaSubscriptions,
    });
    const { collectAffectedDirectRangeDependents, collectSingleAffectedDirectRangeDependent, canApplyDirectAggregateLiteralDelta, canApplyDirectAggregateLiteralDeltaForRequest, collectSingleApplicableDirectAggregateDependent, markAffectedDirectRangeDependents, } = createOperationDirectRangeDependentService({
        workbook: args.state.workbook,
        formulas: args.state.formulas,
        reverseAggregateColumnEdges: args.reverseState.reverseAggregateColumnEdges,
        collectRegionFormulaDependentsForCell: args.collectRegionFormulaDependentsForCell,
        collectSingleRegionFormulaDependentForCell: args.collectSingleRegionFormulaDependentForCell,
        collectSingleRegionFormulaDependentForCellAt: args.collectSingleRegionFormulaDependentForCellAt,
        hasNoCellDependents,
        getSingleEntityDependent: args.getSingleEntityDependent,
        markFormulaChanged: args.markFormulaChanged,
        tryDirectCriteriaSumDelta,
        postRecalcLimit: DIRECT_RANGE_POST_RECALC_LIMIT,
    });
    const canSkipDirtyTraversalForChangedInputs = (changedInputCellIndices, changedInputCount, postRecalcDirectFormulaIndices, options = {}) => {
        return canSkipOperationDirtyTraversalForChangedInputs({
            changedInputCellIndices,
            changedInputCount,
            postRecalcDirectFormulaIndices,
            options,
            access: {
                workbook: args.state.workbook,
                getSingleEntityDependent: args.getSingleEntityDependent,
                getEntityDependents: args.getEntityDependents,
                collectRegionFormulaDependentsForCell: args.collectRegionFormulaDependentsForCell,
                collectAffectedDirectRangeDependents,
                hasTrackedExactLookupDependents,
                hasTrackedSortedLookupDependents,
                hasTrackedDirectRangeDependents,
            },
        });
    };
    const canSkipFormulaColumnVersion = (cellIndex) => {
        if (!hasTrackedColumnDependentsAnywhere()) {
            return true;
        }
        return canSkipOperationFormulaColumnVersion({
            workbook: args.state.workbook,
            cellIndex,
            hasTrackedColumnDependents,
        });
    };
    const { canUseDirectFormulaPostRecalc, markDirectScalarDeltaClosure, markPostRecalcDirectFormulaDependents, markPostRecalcDirectLookupCurrentDependentsFromNumeric, markPostRecalcDirectScalarNumericDependents, tryDirectScalarNumericDeltaFromNumbers, tryMarkDirectScalarLinearDeltaClosure, } = createOperationDirectPostRecalcMarkers({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        getEntityDependents: args.getEntityDependents,
        ...(args.getSingleCellDependent === undefined ? {} : { getSingleCellDependent: args.getSingleCellDependent }),
        ...(args.getCellDependents === undefined ? {} : { getCellDependents: args.getCellDependents }),
        reverseCellEdges: args.reverseState.reverseCellEdges,
        edgeArena: args.edgeArena,
        hasNoCellDependents,
        canSkipAllDirectFormulaColumnVersions: () => !hasTrackedColumnDependentsAnywhere(),
        canSkipDirectFormulaColumnVersion: canSkipFormulaColumnVersion,
        readDirectScalarCellNumber,
        directScalarCellNumericValue,
        directScalarCurrentResultMatchesCell,
        lookupCurrent: {
            canEvaluateDirectUniformLookupCurrentResultFromNumeric,
            tryDirectExactLookupCurrentResult,
            tryDirectUniformLookupCurrentResult,
            tryDirectUniformLookupCurrentResultFromNumeric,
        },
        scalarDeltaClosureLimit: DIRECT_SCALAR_DELTA_CLOSURE_LIMIT,
    });
    const { applyDirectFormulaNumericDelta, applyDirectFormulaNumericDeltaBatch, applyTerminalDirectFormulaNumericDeltaAndReturn, tryApplyDirectFormulaDeltas, tryApplyDirectScalarDeltas, } = createOperationDirectFormulaDeltas({
        state: args.state,
        canSkipTerminalFormulaColumnVersion: canSkipFormulaColumnVersion,
        canSkipDirectFormulaColumnVersion: canSkipFormulaColumnVersion,
    });
    const tryApplySingleDirectAggregateLiteralMutationFastPath = (request) => tryApplySingleDirectAggregateLiteralMutationFastPathWithArgs({
        state: args.state,
        directRangePostRecalcLimit: DIRECT_RANGE_POST_RECALC_LIMIT,
        getSingleEntityDependent: args.getSingleEntityDependent,
        collectAffectedDirectRangeDependents,
        collectSingleApplicableDirectAggregateDependent,
        canApplyDirectAggregateLiteralDeltaForRequest,
        canApplyDirectAggregateLiteralDelta,
        writeFastPathLiteralToExistingCell,
        writeTrustedExistingNumericLiteralToCell,
        applyTerminalDirectFormulaNumericDeltaAndReturn,
        applyDirectFormulaNumericDelta,
        applyDirectFormulaNumericDeltaBatch,
        cellsShareVersionColumn,
        withOptionalColumnVersionBatch,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyTrustedSingleRangeDirectAggregateExistingNumericMutation = (request) => tryApplyTrustedSingleRangeDirectAggregateExistingNumericMutationWithArgs({
        state: args.state,
        directRangePostRecalcLimit: DIRECT_RANGE_POST_RECALC_LIMIT,
        getSingleEntityDependent: args.getSingleEntityDependent,
        collectAffectedDirectRangeDependents,
        collectSingleApplicableDirectAggregateDependent,
        canApplyDirectAggregateLiteralDeltaForRequest,
        canApplyDirectAggregateLiteralDelta,
        writeFastPathLiteralToExistingCell,
        writeTrustedExistingNumericLiteralToCell,
        applyTerminalDirectFormulaNumericDeltaAndReturn,
        applyDirectFormulaNumericDelta,
        applyDirectFormulaNumericDeltaBatch,
        cellsShareVersionColumn,
        withOptionalColumnVersionBatch,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyTrustedColumnDirectAggregateExistingNumericMutation = (request) => tryApplyTrustedColumnDirectAggregateExistingNumericMutationWithArgs({
        state: args.state,
        directRangePostRecalcLimit: DIRECT_RANGE_POST_RECALC_LIMIT,
        getSingleEntityDependent: args.getSingleEntityDependent,
        collectAffectedDirectRangeDependents,
        collectSingleApplicableDirectAggregateDependent,
        canApplyDirectAggregateLiteralDeltaForRequest,
        canApplyDirectAggregateLiteralDelta,
        writeFastPathLiteralToExistingCell,
        writeTrustedExistingNumericLiteralToCell,
        applyTerminalDirectFormulaNumericDeltaAndReturn,
        applyDirectFormulaNumericDelta,
        applyDirectFormulaNumericDeltaBatch,
        cellsShareVersionColumn,
        withOptionalColumnVersionBatch,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyTrustedDirectScalarClosureExistingNumericMutation = (request) => tryApplyTrustedDirectScalarClosureExistingNumericMutationWithArgs({
        state: args.state,
        tryMarkDirectScalarLinearDeltaClosure,
        writeTrustedExistingNumericLiteralToCell,
        tryApplyDirectScalarDeltas,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyTrustedFormulaLeafExistingNumericMutation = (request) => tryApplyTrustedFormulaLeafExistingNumericMutationWithArgs({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        writeTrustedExistingNumericLiteralToCell,
        evaluateFormulaCell: args.evaluateFormulaCell,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyFormulaLeafExistingLiteralMutation = (request) => tryApplyFormulaLeafExistingLiteralMutationWithArgs({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        writeFastPathLiteralToExistingCell,
        evaluateFormulaCell: args.evaluateFormulaCell,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplySingleDirectScalarLiteralMutationWithoutEvents = (request) => tryApplySingleDirectScalarLiteralMutationWithoutEventsWithArgs({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        getEntityDependents: args.getEntityDependents,
        canSkipDirectFormulaColumnVersion: canSkipFormulaColumnVersion,
        canUseDirectFormulaPostRecalc,
        tryDirectScalarNumericDeltaFromNumbers,
        applyDirectFormulaNumericDelta,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplySingleDirectScalarLiteralMutationWithoutEventsAndReturnChanged = (request) => tryApplySingleDirectScalarLiteralMutationWithoutEventsAndReturnChangedWithArgs({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        getEntityDependents: args.getEntityDependents,
        canSkipDirectFormulaColumnVersion: canSkipFormulaColumnVersion,
        canUseDirectFormulaPostRecalc,
        tryDirectScalarNumericDeltaFromNumbers,
        applyDirectFormulaNumericDelta,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplySingleDirectLookupOperandMutationFastPath = (request) => tryApplySingleDirectLookupOperandMutationFastPathWithArgs({
        state: args.state,
        hasNoCellDependents,
        directScalarNumericResultMatchesCell,
        directScalarCurrentResultMatchesCell,
        tryDirectUniformLookupNumericResultFromDescriptor,
        tryDirectApproximateLookupCurrentResultFromNumeric,
        tryDirectExactLookupCurrentResult,
        tryDirectUniformLookupCurrentResultFromNumeric,
        writeTrustedExistingNumericLiteralToCell,
        writeNumericLiteralToExistingCell,
        writeFastPathLiteralToExistingCell,
        applyTerminalDirectFormulaNumericResult,
        applyDirectFormulaCurrentResult,
        cellsShareVersionColumn,
        withOptionalColumnVersionBatch,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
        evaluateDirectFormula: args.evaluateDirectFormula,
    }, request);
    const tryApplySingleDirectFormulaLiteralMutationWithoutEvents = (request) => tryApplySingleDirectFormulaLiteralMutationWithoutEventsWithArgs({
        state: args.state,
        hasNoCellDependents,
        tryDirectUniformLookupNumericResultFromDescriptor,
        directScalarNumericResultMatchesCell,
        tryDirectUniformLookupCurrentResultFromNumeric,
        directScalarCurrentResultMatchesCell,
        canUseDirectFormulaPostRecalc,
        tryDirectScalarNumericDeltaFromNumbers,
        writeFastPathLiteralToExistingCell,
        applyTerminalDirectFormulaNumericResult,
        applyDirectFormulaCurrentResult,
        applyDirectFormulaNumericDelta,
        cellsShareVersionColumn,
        withOptionalColumnVersionBatch,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplySingleKernelSyncOnlyLiteralMutationFastPath = (request) => tryApplySingleKernelSyncOnlyLiteralMutationFastPathWithArgs({
        state: args.state,
        writeFastPathLiteralToExistingCell,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
    }, request);
    const tryApplyFormulaReplacementAsDirectScalarDeltaRoot = (request) => tryApplyOperationFormulaReplacementAsDirectScalarDeltaRoot({
        state: args.state,
        getSingleEntityDependent: args.getSingleEntityDependent,
        evaluateDirectScalarCurrentValue,
        canSkipFormulaColumnVersion,
        applyTerminalDirectFormulaNumericResult,
        tryMarkDirectScalarLinearDeltaClosure,
        applyDirectFormulaCurrentResult,
    }, request);
    let directScalarBatchFastPaths;
    const getDirectScalarBatchFastPaths = () => (directScalarBatchFastPaths ??= createOperationDirectScalarBatchFastPaths({
        state: args.state,
        emitBatch,
        hasVolatileFormulas: args.hasVolatileFormulas,
        hasTrackedExactLookupDependents,
        hasTrackedSortedLookupDependents,
        hasTrackedDirectRangeDependents,
        canFastPathLiteralOverwrite: (cellIndex) => canFastPathLiteralOverwrite(cellIndex),
        canUseDirectFormulaPostRecalc,
        canSkipFormulaColumnVersion,
        directScalarCellNumericValue,
        writeNumericLiteralToCellStore,
        applyTerminalDirectFormulaNumericResult,
        applyTerminalDirectFormulaNumericResults,
        applyTerminalDirectFormulaAffineNumericResults,
        applyTerminalDirectFormulaAffineNumericResultsFromRefs,
        applyDirectFormulaNumericResult,
        applyDirectFormulaCurrentResult,
        tryEvaluateDirectScalarWithPendingNumbers,
        tryEvaluateDirectScalarNumericWithPendingNumbers,
        planExactLookupNumericColumnWrite,
        planApproximateLookupNumericColumnWrite,
        getSingleEntityDependent: args.getSingleEntityDependent,
        getEntityDependents: args.getEntityDependents,
        materializeDeferredStructuralFormulaSources: args.materializeDeferredStructuralFormulaSources,
        beginMutationCollection: args.beginMutationCollection,
        ensureRecalcScratchCapacity: args.ensureRecalcScratchCapacity,
        resetMaterializedCellScratch: args.resetMaterializedCellScratch,
        getBatchMutationDepth: args.getBatchMutationDepth,
        setBatchMutationDepth: args.setBatchMutationDepth,
        markInputChanged: args.markInputChanged,
        markExplicitChanged: args.markExplicitChanged,
        getChangedInputBuffer: args.getChangedInputBuffer,
        deferKernelSync: args.deferKernelSync,
        composeDisjointEventChanges: args.composeDisjointEventChanges,
        captureChangedCells: args.captureChangedCells,
        invalidateExactLookupColumn: args.invalidateExactLookupColumn,
        invalidateSortedLookupColumn: args.invalidateSortedLookupColumn,
    }));
    const tryApplyCoalescedDirectScalarLiteralBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyCoalescedDirectScalarLiteralBatch(...input);
    const tryApplyDenseRowPairDirectScalarLiteralBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyDenseRowPairDirectScalarLiteralBatch(...input);
    const tryApplyLookupOnlyNumericColumnLiteralBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyLookupOnlyNumericColumnLiteralBatch(...input);
    const tryApplyDenseRectangularDirectAggregateLiteralBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyDenseRectangularDirectAggregateLiteralBatch(...input);
    const tryApplyFreshDenseRectangularNumericLiteralBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyFreshDenseRectangularNumericLiteralBatch(...input);
    const tryApplyExistingNumericDirectScalarBatch = (...input) => getDirectScalarBatchFastPaths().tryApplyExistingNumericDirectScalarBatch(...input);
    let singleExistingLiteralFastPath;
    const getSingleExistingLiteralFastPath = () => (singleExistingLiteralFastPath ??= createOperationSingleExistingLiteralFastPath({
        state: args.state,
        hasVolatileFormulas: args.hasVolatileFormulas,
        getSingleEntityDependent: args.getSingleEntityDependent,
        noteAggregateLiteralWrite: args.noteAggregateLiteralWrite,
        evaluateDirectFormula: args.evaluateDirectFormula,
        invalidateExactLookupColumn: args.invalidateExactLookupColumn,
        invalidateSortedLookupColumn: args.invalidateSortedLookupColumn,
        hasTrackedExactLookupDependents,
        hasTrackedSortedLookupDependents,
        hasTrackedDirectRangeDependents,
        hasTrackedColumnDependentsAnywhere,
        collectRegionFormulaDependentsForCell: args.collectRegionFormulaDependentsForCell,
        collectSingleRegionFormulaDependentForCell: args.collectSingleRegionFormulaDependentForCell,
        collectSingleRegionFormulaDependentForCellAt: args.collectSingleRegionFormulaDependentForCellAt,
        canSkipApproximateLookupNewNumericColumnWrite,
        writeNumericLiteralToExistingCell,
        deferSingleCellKernelSync,
        makeSingleLiteralSkipMetrics,
        canFastPathLiteralOverwrite: (cellIndex) => canFastPathLiteralOverwrite(cellIndex),
        directScalarCellNumericValue,
        tryApplyTrustedSingleRangeDirectAggregateExistingNumericMutation,
        tryApplyTrustedColumnDirectAggregateExistingNumericMutation,
        tryApplyTrustedDirectScalarClosureExistingNumericMutation,
        tryApplyTrustedFormulaLeafExistingNumericMutation,
        tryApplyFormulaLeafExistingLiteralMutation,
        tryApplySingleDirectAggregateLiteralMutationFastPath,
        planExactLookupNumericColumnWrite,
        planApproximateLookupNumericColumnWrite,
        patchUniformLookupTailWrites,
        tryApplySingleKernelSyncOnlyLiteralMutationFastPath,
        tryApplySingleDirectFormulaLiteralMutationWithoutEvents,
        tryApplySingleDirectScalarLiteralMutationWithoutEvents,
        tryApplySingleDirectScalarLiteralMutationWithoutEventsAndReturnChanged,
        tryApplySingleDirectLookupOperandMutationFastPath,
        markPostRecalcDirectScalarNumericDependents,
        tryMarkDirectScalarLinearDeltaClosure,
        collectSingleAffectedDirectRangeDependent,
        collectAffectedDirectRangeDependents,
        applyDirectFormulaCurrentResult,
        applyDirectFormulaNumericDelta,
        applyDirectScalarCurrentValue,
        tryApplyDirectScalarDeltas,
        tryApplyDirectFormulaDeltas,
        countPostRecalcDirectFormulaMetric: (cellIndex, counts) => countPostRecalcDirectFormulaMetric(cellIndex, counts),
        hasDynamicFormulaDependents,
    }));
    const tryApplySingleExistingDirectLiteralMutation = (...input) => getSingleExistingLiteralFastPath().tryApplySingleExistingDirectLiteralMutation(...input);
    const applyExistingNumericCellMutationAtNow = (...input) => getSingleExistingLiteralFastPath().applyExistingNumericCellMutationAtNow(...input);
    const applyExistingLiteralCellMutationAtNow = (...input) => getSingleExistingLiteralFastPath().applyExistingLiteralCellMutationAtNow(...input);
    const countPostRecalcDirectFormulaMetric = (cellIndex, counts) => {
        countOperationPostRecalcDirectFormulaMetric({
            formulas: args.state.formulas,
            cellIndex,
            counts,
        });
    };
    const refreshDependentRangesAndRebindFormulaDependents = (cellIndex, formulaChangedCount) => {
        return refreshDependentRangesAndRebindOperationFormulaDependents({
            cellIndex,
            formulaChangedCount,
            getEntityDependents: args.getEntityDependents,
            collectFormulaDependents: args.collectFormulaDependents,
            refreshRangeDependencies: args.refreshRangeDependencies,
            rebindFormulaCells: args.rebindFormulaCells,
        });
    };
    let derivedOpApplier;
    const getDerivedOpApplier = () => (derivedOpApplier ??= createOperationDerivedOpApplier({
        state: {
            workbook: args.state.workbook,
            replicaState: args.state.replicaState,
        },
        reverseSpillEdges: args.reverseState.reverseSpillEdges,
        setEntityVersionForOp,
        materializePivot: args.materializePivot,
        clearOwnedPivot: args.clearOwnedPivot,
        rebindFormulaCells: args.rebindFormulaCells,
    }));
    const applyDerivedOpNow = (...input) => getDerivedOpApplier().applyDerivedOpNow(...input);
    const applySpillRangeOp = (...input) => getDerivedOpApplier().applySpillRangeOp(...input);
    const applyPivotUpsertOp = (...input) => getDerivedOpApplier().applyPivotUpsertOp(...input);
    const applyPivotDeleteOp = (...input) => getDerivedOpApplier().applyPivotDeleteOp(...input);
    let batchApplier;
    const getBatchApplier = () => (batchApplier ??= createOperationBatchApplier({
        serviceArgs: args,
        emitBatch,
        replicaVersionWriter,
        isNullLiteralWriteNoOp,
        isClearCellNoOp,
        readCellValueForLookup,
        readExactNumericValueForLookup,
        hasTrackedExactLookupDependents,
        hasTrackedSortedLookupDependents,
        hasTrackedDirectRangeDependents,
        planExactLookupNumericColumnWrite,
        planApproximateLookupNumericColumnWrite,
        noteExactLookupLiteralWriteWhenDirty,
        noteSortedLookupLiteralWriteWhenDirty,
        markAffectedDirectRangeDependents,
        markPostRecalcDirectFormulaDependents,
        markDirectScalarDeltaClosure,
        collectAffectedDirectRangeDependents,
        tryApplyFormulaReplacementAsDirectScalarDeltaRoot,
        rebindDynamicFormulaDependents,
        refreshDependentRangesAndRebindFormulaDependents,
        pruneCellIfOrphaned,
        normalizeHistoryDependencyPlaceholder,
        markCycleMemberInputsChanged,
        hasCycleMembersNow,
        canSkipDirtyTraversalForChangedInputs,
        directFormulaCallbacks: {
            applyDirectFormulaCurrentResult,
            applyDirectFormulaNumericDelta,
            applyDirectScalarCurrentValue,
            tryApplyDirectScalarDeltas,
            tryApplyDirectFormulaDeltas,
            countPostRecalcDirectFormulaMetric,
        },
        applySpillRangeOp,
        applyPivotUpsertOp,
        applyPivotDeleteOp,
    }));
    const withOperationEvaluationBudget = (run) => {
        args.beginEvaluationBudget(performance.now());
        try {
            args.checkEvaluationBudget();
            return run();
        }
        finally {
            args.endEvaluationBudget();
        }
    };
    const applyBatchNow = (...input) => withOperationEvaluationBudget(() => getBatchApplier().applyBatchNow(...input));
    const applyLocalSingleStructuralAxisOpWithoutBatchNow = (...input) => withOperationEvaluationBudget(() => getBatchApplier().applyLocalSingleStructuralAxisOpWithoutBatchNow(...input));
    const applyCellMutationsAtNowCore = createOperationCellMutationApplier({
        serviceArgs: args,
        emitBatch,
        setCellEntityVersion,
        isNullLiteralWriteNoOp,
        isClearCellNoOp,
        canFastPathLiteralOverwrite,
        tryApplySingleExistingDirectLiteralMutation,
        tryApplyCoalescedDirectScalarLiteralBatch,
        tryApplyFreshDenseRectangularNumericLiteralBatch,
        writeNumericLiteralToCellStore,
        readCellValueForLookup,
        readApproximateNumericValueForLookup,
        readExactNumericValueForLookup,
        hasTrackedExactLookupDependents,
        hasTrackedSortedLookupDependents,
        hasTrackedDirectRangeDependents,
        planExactLookupNumericColumnWrite,
        planApproximateLookupNumericColumnWrite,
        noteExactLookupLiteralWriteWhenDirty,
        noteSortedLookupLiteralWriteWhenDirty,
        markAffectedDirectRangeDependents,
        collectAffectedDirectRangeDependents,
        markPostRecalcDirectFormulaDependents,
        markDirectScalarDeltaClosure,
        markPostRecalcDirectScalarNumericDependents,
        markPostRecalcDirectLookupCurrentDependentsFromNumeric,
        rebindDynamicFormulaDependents,
        directScalarCellNumericValue,
        tryApplyFormulaReplacementAsDirectScalarDeltaRoot,
        markCycleMemberInputsChanged,
        hasCycleMembersNow,
        canSkipDirtyTraversalForChangedInputs,
        directFormulaCallbacks: {
            applyDirectFormulaCurrentResult,
            applyDirectFormulaNumericDelta,
            applyDirectScalarCurrentValue,
            tryApplyDirectScalarDeltas,
            tryApplyDirectFormulaDeltas,
            countPostRecalcDirectFormulaMetric,
        },
        applyDirectFormulaNumericResult,
        pruneCellIfOrphaned,
        normalizeHistoryDependencyPlaceholder,
    });
    const applyCellMutationsAtNow = (...input) => withOperationEvaluationBudget(() => applyCellMutationsAtNowCore(...input));
    const applyExistingNumericCellMutationsAtNow = (...input) => withOperationEvaluationBudget(() => tryApplyExistingNumericDirectScalarBatch(...input));
    const __testHooks = ENGINE_OPERATION_TEST_HOOKS_ENABLED
        ? {
            canPatchUniformLookupTailWrite,
            canSkipApproximateLookupDirtyMark,
            canSkipApproximateLookupNewNumericColumnWrite,
            canSkipApproximateLookupNumericColumnWrite,
            canSkipExactLookupNumericColumnWrite,
            collectAffectedDirectRangeDependents,
            collectSingleAffectedDirectRangeDependent,
            directCriteriaMatchesChangedAggregateRow,
            isLocallySortedNumericWrite,
            isLocallySortedTextWrite,
            markAffectedApproximateLookupDependents,
            markAffectedDirectRangeDependents,
            patchUniformLookupTailWrites,
            planApproximateLookupNumericColumnWrite,
            planExactLookupNumericColumnWrite,
            planSingleApproximateLookupNumericColumnWrite,
            planSingleExactLookupNumericColumnWrite,
            readApproximateNumericValueAtForLookup,
            readApproximateNumericValueForLookup,
            readCellValueAtForLookup,
            readCellValueForLookup,
            readDirectCriteriaOperandValue,
            readExactNumericValueForLookup,
            tryApplyDenseRowPairDirectScalarLiteralBatch,
            tryApplyLookupOnlyNumericColumnLiteralBatch,
            tryApplyDenseRectangularDirectAggregateLiteralBatch,
            tryApplyFreshDenseRectangularNumericLiteralBatch,
            tryApplySingleExistingDirectLiteralMutation,
            tryApplySingleDirectAggregateLiteralMutationFastPath,
            tryApplySingleDirectFormulaLiteralMutationWithoutEvents,
            tryApplySingleDirectLookupOperandMutationFastPath,
            tryApplySingleDirectScalarLiteralMutationWithoutEvents,
            tryApplySingleKernelSyncOnlyLiteralMutationFastPath,
            tryDirectCriteriaSumDelta,
        }
        : {};
    return {
        __testHooks,
        applyBatchNow,
        applyLocalSingleStructuralAxisOpWithoutBatchNow,
        applyBatch(batch, source, potentialNewCells, preparedCellAddressesByOpIndex) {
            return Effect.try({
                try: () => {
                    applyBatchNow(batch, source, potentialNewCells, preparedCellAddressesByOpIndex);
                },
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to apply ${source} batch`, cause),
                    cause,
                }),
            });
        },
        applyCellMutationsAt(refs, batch, source, potentialNewCells) {
            return Effect.try({
                try: () => {
                    applyCellMutationsAtNow(refs, batch, source, potentialNewCells);
                },
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to apply ${source} cell mutations`, cause),
                    cause,
                }),
            });
        },
        applyCellMutationsAtNow,
        applyExistingNumericCellMutationsAtNow,
        applyExistingNumericCellMutationAtNow,
        applyExistingLiteralCellMutationAtNow,
        applyDerivedOp(op) {
            return Effect.try({
                try: () => applyDerivedOpNow(op),
                catch: (cause) => new EngineMutationError({
                    message: mutationErrorMessage(`Failed to apply derived operation ${op.kind}`, cause),
                    cause,
                }),
            });
        },
    };
}
//# sourceMappingURL=operation-service.js.map