import { parseCellAddress } from '@bilig/formula';
import { emptyValue, literalToValue, writeLiteralToCellStore } from '../../engine-value-utils.js';
import { exactLookupLiteralNumericValue, normalizeApproximateNumericValue, normalizeExactNumericValue, withOptionalLookupStringIds, } from './direct-lookup-helpers.js';
import { directScalarLiteralNumericValue } from './direct-scalar-helpers.js';
import { cellTouchesOperationPivotSource } from './operation-pivot-source-helpers.js';
import { applyOperationLookupNumericWriteTailPatches, planOperationLookupNumericWrites } from './operation-lookup-write-plans.js';
import { applyTableHeaderRenameForSetCellValue, isWorkbookTableHeaderCell } from './operation-table-header-rename.js';
export function applyBatchSetCellValueOp(request) {
    const args = request.serviceArgs;
    const { op, preparedCellAddress } = request;
    const existingIndex = request.preparedCells.getExistingCellIndex(op.sheetName, op.address, preparedCellAddress);
    const parsedAddress = preparedCellAddress ?? parseCellAddress(op.address, op.sheetName);
    const sheet = args.state.workbook.getSheet(op.sheetName);
    const sheetId = sheet?.id;
    const hasExactLookupDependents = sheetId !== undefined ? request.hasTrackedExactLookupDependents(sheetId, parsedAddress.col) : false;
    const hasSortedLookupDependents = sheetId !== undefined ? request.hasTrackedSortedLookupDependents(sheetId, parsedAddress.col) : false;
    const hasAggregateDependents = sheetId !== undefined ? request.hasTrackedDirectRangeDependents(sheetId, parsedAddress.col) : false;
    let changedInputCount = request.changedInputCount;
    let formulaChangedCount = request.formulaChangedCount;
    let explicitChangedCount = request.explicitChangedCount;
    let topologyChanged = request.topologyChanged;
    let refreshAllPivots = request.refreshAllPivots;
    let effectiveValue = op.value;
    if (!request.isRestore &&
        cellTouchesOperationPivotSource({
            workbook: args.state.workbook,
            sheetName: op.sheetName,
            row: parsedAddress.row,
            col: parsedAddress.col,
        })) {
        refreshAllPivots = true;
    }
    if (!request.isRestore) {
        if (op.value === null &&
            (existingIndex === undefined || request.isNullLiteralWriteNoOp(existingIndex)) &&
            !isWorkbookTableHeaderCell(args.state.workbook, op.sheetName, parsedAddress.row, parsedAddress.col)) {
            return { changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots };
        }
        ;
        ({
            formulaChangedCount,
            topologyChanged,
            value: effectiveValue,
        } = applyTableHeaderRenameForSetCellValue({
            serviceArgs: args,
            sheetName: op.sheetName,
            row: parsedAddress.row,
            col: parsedAddress.col,
            value: op.value,
            formulaChangedCount,
            topologyChanged,
        }));
        if (existingIndex !== undefined) {
            changedInputCount = args.markPivotRootsChanged(args.clearPivotForCell(existingIndex), changedInputCount);
        }
    }
    const needsLookupValueRead = hasExactLookupDependents || hasSortedLookupDependents || hasAggregateDependents;
    const prior = request.readCellValueForLookup(existingIndex);
    const oldExactLookupNumber = hasExactLookupDependents ? normalizeExactNumericValue(prior.value) : undefined;
    const newExactLookupNumber = hasExactLookupDependents ? exactLookupLiteralNumericValue(effectiveValue) : undefined;
    const oldApproximateLookupNumber = hasSortedLookupDependents ? normalizeApproximateNumericValue(prior.value) : undefined;
    const newApproximateLookupNumber = hasSortedLookupDependents ? directScalarLiteralNumericValue(effectiveValue) : undefined;
    const lookupWritePlans = sheetId === undefined
        ? undefined
        : planOperationLookupNumericWrites({
            isRestore: request.isRestore,
            hasAggregateDependents,
            hasExactLookupDependents,
            hasSortedLookupDependents,
            sheetId,
            sheetName: op.sheetName,
            row: parsedAddress.row,
            col: parsedAddress.col,
            oldExactLookupNumber,
            newExactLookupNumber,
            oldApproximateLookupNumber,
            newApproximateLookupNumber,
            planner: {
                planExactLookupNumericColumnWrite: request.planExactLookupNumericColumnWrite,
                planApproximateLookupNumericColumnWrite: request.planApproximateLookupNumericColumnWrite,
            },
        });
    const exactLookupDependentsHandled = lookupWritePlans?.exactHandled === true;
    const sortedLookupDependentsHandled = lookupWritePlans?.sortedHandled === true;
    const cellIndex = request.preparedCells.ensureCellTracked(op.sheetName, op.address, preparedCellAddress);
    if (!request.isRestore) {
        const clearedSpill = args.clearSpillForCell(cellIndex);
        changedInputCount = args.markSpillRootsChanged(clearedSpill.changedCellIndices, changedInputCount);
        if (clearedSpill.ownerCellIndex !== undefined) {
            formulaChangedCount = args.markFormulaChanged(clearedSpill.ownerCellIndex, formulaChangedCount);
        }
        const removedFormula = args.removeFormula(cellIndex);
        if (removedFormula) {
            args.invalidateAggregateColumn({ sheetName: op.sheetName, col: parsedAddress.col });
            request.clearLookupImpactCaches();
            formulaChangedCount = request.refreshDependentRangesAndRebindFormulaDependents(cellIndex, formulaChangedCount);
        }
        topologyChanged = removedFormula || topologyChanged;
    }
    writeLiteralToCellStore(args.state.workbook.cellStore, cellIndex, effectiveValue, args.state.strings);
    if (effectiveValue === null) {
        args.state.workbook.cellStore.flags[cellIndex] = (args.state.workbook.cellStore.flags[cellIndex] ?? 0) | 256 /* CellFlags.AuthoredBlank */;
    }
    args.state.workbook.notifyCellValueWritten(cellIndex);
    if (request.allowLookupTailPatch && lookupWritePlans?.handledLookupDependents === true) {
        const columnVersionAfterWrite = sheet?.columnVersions[parsedAddress.col] ?? 0;
        applyOperationLookupNumericWriteTailPatches(lookupWritePlans, {
            row: parsedAddress.row,
            oldExactLookupNumber,
            newExactLookupNumber,
            oldApproximateLookupNumber,
            newApproximateLookupNumber,
            columnVersionAfterWrite,
        });
    }
    if (!request.isRestore) {
        ;
        ({ changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots } =
            request.rebindValueSensitiveFormulaDependents(cellIndex, {
                changedInputCount,
                formulaChangedCount,
                explicitChangedCount,
                topologyChanged,
                refreshAllPivots,
            }));
    }
    if (needsLookupValueRead) {
        const formulaChangedCountBeforeLookupNotes = formulaChangedCount;
        const newValue = literalToValue(effectiveValue, args.state.strings);
        const newStringId = typeof effectiveValue === 'string' ? args.state.workbook.cellStore.stringIds[cellIndex] : undefined;
        if (!request.isRestore) {
            const directDependentsHandled = request.markPostRecalcDirectFormulaDependents(cellIndex, request.postRecalcDirectFormulaIndices, prior.value, newValue);
            if (!directDependentsHandled) {
                request.markDirectScalarDeltaClosure(cellIndex, prior.value, newValue, request.postRecalcDirectFormulaIndices);
            }
        }
        if (hasExactLookupDependents || hasAggregateDependents) {
            const exactLookupRequest = withOptionalLookupStringIds({
                sheetName: op.sheetName,
                row: parsedAddress.row,
                col: parsedAddress.col,
                oldValue: prior.value,
                newValue,
                oldStringId: prior.stringId,
                newStringId,
                inputCellIndex: cellIndex,
            });
            if (hasExactLookupDependents && exactLookupDependentsHandled) {
                args.noteExactLookupLiteralWrite(exactLookupRequest);
            }
            else if (hasExactLookupDependents) {
                formulaChangedCount = request.noteExactLookupLiteralWriteWhenDirty(exactLookupRequest, formulaChangedCount, request.exactLookupImpactCaches);
            }
            if (hasAggregateDependents) {
                args.noteAggregateLiteralWrite({
                    sheetName: exactLookupRequest.sheetName,
                    row: exactLookupRequest.row,
                    col: exactLookupRequest.col,
                    oldValue: exactLookupRequest.oldValue,
                    newValue: exactLookupRequest.newValue,
                });
                formulaChangedCount = request.markAffectedDirectRangeDependents(exactLookupRequest, formulaChangedCount, request.postRecalcDirectFormulaIndices);
            }
        }
        if (hasSortedLookupDependents) {
            const sortedLookupRequest = withOptionalLookupStringIds({
                sheetName: op.sheetName,
                row: parsedAddress.row,
                col: parsedAddress.col,
                oldValue: prior.value,
                newValue,
                oldStringId: prior.stringId,
                newStringId,
            });
            if (sortedLookupDependentsHandled) {
                args.noteSortedLookupLiteralWrite(sortedLookupRequest);
            }
            else {
                formulaChangedCount = request.noteSortedLookupLiteralWriteWhenDirty(sortedLookupRequest, formulaChangedCount);
            }
        }
        if (!hasAggregateDependents &&
            (hasExactLookupDependents || hasSortedLookupDependents) &&
            formulaChangedCount === formulaChangedCountBeforeLookupNotes) {
            request.lookupHandledInputCellIndices.push(cellIndex);
        }
    }
    else if (!request.isRestore) {
        const newValue = literalToValue(effectiveValue, args.state.strings);
        const directDependentsHandled = request.markPostRecalcDirectFormulaDependents(cellIndex, request.postRecalcDirectFormulaIndices, prior.value, newValue);
        if (!directDependentsHandled) {
            request.markDirectScalarDeltaClosure(cellIndex, prior.value, newValue, request.postRecalcDirectFormulaIndices);
        }
    }
    args.state.workbook.cellStore.flags[cellIndex] =
        (args.state.workbook.cellStore.flags[cellIndex] ?? 0) &
            ~(2 /* CellFlags.HasFormula */ | 4 /* CellFlags.JsOnly */ | 8 /* CellFlags.InCycle */ | 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */);
    if (!request.isRestore && effectiveValue === null) {
        request.pruneCellIfOrphaned(cellIndex);
    }
    changedInputCount = args.markInputChanged(cellIndex, changedInputCount);
    if (!request.isRestore) {
        explicitChangedCount = args.markExplicitChanged(cellIndex, explicitChangedCount);
        request.setEntityVersionForOp(op, request.order);
    }
    return { changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots };
}
export function applyBatchClearCellOp(request) {
    const args = request.serviceArgs;
    const { op, preparedCellAddress } = request;
    let cellIndex = request.preparedCells.getExistingCellIndex(op.sheetName, op.address, preparedCellAddress);
    const parsedAddress = preparedCellAddress ?? parseCellAddress(op.address, op.sheetName);
    const sheet = args.state.workbook.getSheet(op.sheetName);
    const sheetId = sheet?.id;
    const hasExactLookupDependents = sheetId !== undefined ? request.hasTrackedExactLookupDependents(sheetId, parsedAddress.col) : false;
    const hasSortedLookupDependents = sheetId !== undefined ? request.hasTrackedSortedLookupDependents(sheetId, parsedAddress.col) : false;
    const hasAggregateDependents = sheetId !== undefined ? request.hasTrackedDirectRangeDependents(sheetId, parsedAddress.col) : false;
    const needsLookupValueRead = hasExactLookupDependents || hasSortedLookupDependents || hasAggregateDependents;
    let changedInputCount = request.changedInputCount;
    let formulaChangedCount = request.formulaChangedCount;
    let explicitChangedCount = request.explicitChangedCount;
    let topologyChanged = request.topologyChanged;
    let refreshAllPivots = request.refreshAllPivots;
    let headerClearValue;
    if (!request.isRestore &&
        cellTouchesOperationPivotSource({
            workbook: args.state.workbook,
            sheetName: op.sheetName,
            row: parsedAddress.row,
            col: parsedAddress.col,
        })) {
        refreshAllPivots = true;
    }
    if (!request.isRestore && isWorkbookTableHeaderCell(args.state.workbook, op.sheetName, parsedAddress.row, parsedAddress.col)) {
        const renamed = applyTableHeaderRenameForSetCellValue({
            serviceArgs: args,
            sheetName: op.sheetName,
            row: parsedAddress.row,
            col: parsedAddress.col,
            value: null,
            formulaChangedCount,
            topologyChanged,
        });
        formulaChangedCount = renamed.formulaChangedCount;
        topologyChanged = renamed.topologyChanged;
        headerClearValue = String(renamed.value ?? '');
    }
    const prior = request.readCellValueForLookup(cellIndex);
    const nextValue = headerClearValue === undefined ? emptyValue() : literalToValue(headerClearValue, args.state.strings);
    if (cellIndex === undefined) {
        if (headerClearValue !== undefined) {
            cellIndex = request.preparedCells.ensureCellTracked(op.sheetName, op.address, preparedCellAddress);
            writeLiteralToCellStore(args.state.workbook.cellStore, cellIndex, headerClearValue, args.state.strings);
            args.state.workbook.notifyCellValueWritten(cellIndex);
            if (!request.isRestore) {
                ;
                ({ changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots } =
                    request.rebindValueSensitiveFormulaDependents(cellIndex, {
                        changedInputCount,
                        formulaChangedCount,
                        explicitChangedCount,
                        topologyChanged,
                        refreshAllPivots,
                    }));
            }
            changedInputCount = args.markInputChanged(cellIndex, changedInputCount);
            explicitChangedCount = args.markExplicitChanged(cellIndex, explicitChangedCount);
        }
        request.setEntityVersionForOp(op, request.order);
        return { changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots };
    }
    const targetCellIndex = cellIndex;
    if (headerClearValue === undefined && request.isClearCellNoOp(targetCellIndex)) {
        return { changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots };
    }
    changedInputCount = args.markPivotRootsChanged(args.clearPivotForCell(targetCellIndex), changedInputCount);
    const clearedSpill = args.clearSpillForCell(targetCellIndex);
    changedInputCount = args.markSpillRootsChanged(clearedSpill.changedCellIndices, changedInputCount);
    if (clearedSpill.ownerCellIndex !== undefined) {
        formulaChangedCount = args.markFormulaChanged(clearedSpill.ownerCellIndex, formulaChangedCount);
    }
    const removedFormula = args.removeFormula(targetCellIndex);
    if (removedFormula) {
        args.invalidateAggregateColumn({ sheetName: op.sheetName, col: parsedAddress.col });
        request.clearLookupImpactCaches();
        formulaChangedCount = request.refreshDependentRangesAndRebindFormulaDependents(targetCellIndex, formulaChangedCount);
    }
    topologyChanged = removedFormula || topologyChanged;
    if (headerClearValue === undefined) {
        args.state.workbook.cellStore.setValue(targetCellIndex, emptyValue());
    }
    else {
        writeLiteralToCellStore(args.state.workbook.cellStore, targetCellIndex, headerClearValue, args.state.strings);
    }
    args.state.workbook.notifyCellValueWritten(targetCellIndex);
    if (!request.isRestore) {
        ;
        ({ changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots } =
            request.rebindValueSensitiveFormulaDependents(targetCellIndex, {
                changedInputCount,
                formulaChangedCount,
                explicitChangedCount,
                topologyChanged,
                refreshAllPivots,
            }));
        const directDependentsHandled = request.markPostRecalcDirectFormulaDependents(targetCellIndex, request.postRecalcDirectFormulaIndices, prior.value, nextValue);
        if (!directDependentsHandled) {
            request.markDirectScalarDeltaClosure(targetCellIndex, prior.value, nextValue, request.postRecalcDirectFormulaIndices);
        }
    }
    if (needsLookupValueRead) {
        if (hasExactLookupDependents || hasAggregateDependents) {
            const exactLookupRequest = withOptionalLookupStringIds({
                sheetName: op.sheetName,
                row: parsedAddress.row,
                col: parsedAddress.col,
                oldValue: prior.value,
                newValue: nextValue,
                oldStringId: prior.stringId,
                newStringId: headerClearValue === undefined ? undefined : args.state.workbook.cellStore.stringIds[targetCellIndex],
                inputCellIndex: targetCellIndex,
            });
            if (hasExactLookupDependents) {
                formulaChangedCount = request.noteExactLookupLiteralWriteWhenDirty(exactLookupRequest, formulaChangedCount, request.exactLookupImpactCaches);
            }
            if (hasAggregateDependents) {
                args.noteAggregateLiteralWrite({
                    sheetName: exactLookupRequest.sheetName,
                    row: exactLookupRequest.row,
                    col: exactLookupRequest.col,
                    oldValue: exactLookupRequest.oldValue,
                    newValue: exactLookupRequest.newValue,
                });
                formulaChangedCount = request.markAffectedDirectRangeDependents(exactLookupRequest, formulaChangedCount, request.postRecalcDirectFormulaIndices);
            }
        }
        if (hasSortedLookupDependents) {
            const sortedLookupRequest = withOptionalLookupStringIds({
                sheetName: op.sheetName,
                row: parsedAddress.row,
                col: parsedAddress.col,
                oldValue: prior.value,
                newValue: nextValue,
                oldStringId: prior.stringId,
                newStringId: headerClearValue === undefined ? undefined : args.state.workbook.cellStore.stringIds[targetCellIndex],
            });
            formulaChangedCount = request.noteSortedLookupLiteralWriteWhenDirty(sortedLookupRequest, formulaChangedCount);
        }
    }
    args.state.workbook.cellStore.flags[targetCellIndex] =
        (args.state.workbook.cellStore.flags[targetCellIndex] ?? 0) &
            ~(2 /* CellFlags.HasFormula */ | 4 /* CellFlags.JsOnly */ | 8 /* CellFlags.InCycle */ | 64 /* CellFlags.SpillChild */ | 128 /* CellFlags.PivotOutput */);
    if (headerClearValue === undefined) {
        args.state.workbook.cellStore.flags[targetCellIndex] &= ~256 /* CellFlags.AuthoredBlank */;
    }
    request.normalizeHistoryDependencyPlaceholder(targetCellIndex, request.source);
    if (headerClearValue === undefined) {
        request.pruneCellIfOrphaned(targetCellIndex);
    }
    changedInputCount = args.markInputChanged(targetCellIndex, changedInputCount);
    explicitChangedCount = args.markExplicitChanged(targetCellIndex, explicitChangedCount);
    request.setEntityVersionForOp(op, request.order);
    return { changedInputCount, formulaChangedCount, explicitChangedCount, topologyChanged, refreshAllPivots };
}
//# sourceMappingURL=operation-batch-cell-value-mutations.js.map