import { renameCompiledFormulaSheetReferences, renameCompiledFormulaSheetReferenceMetadata, renameCompiledFormulaSheetReferenceMetadataInPlace, } from '@bilig/formula';
import { canRewriteCompiledPreservingBindings, canRewriteCompiledPreservingDirectAggregate, canRewriteCompiledPreservingDirectScalar, } from './formula-binding-shape-helpers.js';
import { buildDirectScalarDescriptor } from './formula-binding-direct-scalar.js';
import { appendSheetRenameSourceTransformRecord } from './formula-binding-dependency-helpers.js';
function renameDirectAggregateDescriptorSheetForRuntime(descriptor, oldSheetName, newSheetName) {
    if (descriptor.sheetName === oldSheetName) {
        ;
        descriptor.sheetName = newSheetName;
    }
    return descriptor;
}
function appendSheetRenameSourceTransformForRuntime(formula, transform) {
    if (formula.sourceRenameTransform === undefined && formula.sourceRenameTransforms === undefined) {
        formula.sourceRenameTransform = transform;
        return;
    }
    appendSheetRenameSourceTransformRecord(formula, transform);
}
export function createFormulaBindingSheetRenameHandler(args) {
    const deferCellFormulasForSheetRenameNow = (oldSheetName, newSheetName) => {
        args.formulaSheetIndex.moveOwnerSheetName(oldSheetName, newSheetName);
        const references = args.formulaSheetIndex.moveReferenceSheetName(oldSheetName, newSheetName);
        if (references.size > 0) {
            const sourceTransform = { oldSheetName, newSheetName };
            for (const cellIndex of references) {
                const formula = args.serviceArgs.state.formulas.get(cellIndex);
                if (!formula) {
                    continue;
                }
                appendSheetRenameSourceTransformForRuntime(formula, sourceTransform);
                if (formula.directAggregate !== undefined) {
                    formula.directAggregate = renameDirectAggregateDescriptorSheetForRuntime(formula.directAggregate, oldSheetName, newSheetName);
                }
            }
        }
    };
    const rewriteCellFormulasForSheetRenameNow = (oldSheetName, newSheetName, formulaChangedCount) => {
        const sourceTransform = { oldSheetName, newSheetName };
        const referencedCandidates = args.formulaSheetIndex.getReferencingSheetSet(oldSheetName);
        const ownerCandidates = args.formulaSheetIndex.getOwnedBySheetSet(oldSheetName);
        const seen = [];
        let seenSet;
        const rewriteCandidate = (cellIndex) => {
            if (seenSet) {
                if (seenSet.has(cellIndex)) {
                    return;
                }
                seenSet.add(cellIndex);
            }
            else {
                for (let index = 0; index < seen.length; index += 1) {
                    if (seen[index] === cellIndex) {
                        return;
                    }
                }
                seen.push(cellIndex);
                if (seen.length > 8) {
                    seenSet = new Set(seen);
                }
            }
            const formula = args.serviceArgs.state.formulas.get(cellIndex);
            if (!formula) {
                return;
            }
            const referencedByOldSheet = referencedCandidates?.has(cellIndex) === true;
            const ownerSheetName = args.serviceArgs.state.workbook.getSheetNameById(args.serviceArgs.state.workbook.cellStore.sheetIds[cellIndex]);
            if (!ownerSheetName) {
                return;
            }
            const previousOwnerSheetName = ownerSheetName === newSheetName ? oldSheetName : ownerSheetName;
            if (args.serviceArgs.compiledPlans.isSoleOwner(formula.planId, formula.compiled) &&
                formula.compiled.symbolicNames.length === 0 &&
                formula.compiled.symbolicTables.length === 0 &&
                formula.compiled.symbolicSpills.length === 0 &&
                formula.directLookup === undefined &&
                formula.directCriteria === undefined &&
                (formula.directAggregate !== undefined || args.rangeDependenciesHaveNoFormulaMembers(formula.rangeDependencies))) {
                if (previousOwnerSheetName !== ownerSheetName) {
                    args.formulaSheetIndex.removeOwner(previousOwnerSheetName, cellIndex);
                }
                const sourceChanged = renameCompiledFormulaSheetReferenceMetadataInPlace(formula.compiled, oldSheetName, newSheetName);
                if (sourceChanged) {
                    args.formulaSheetIndex.removeReference(oldSheetName, cellIndex);
                    appendSheetRenameSourceTransformForRuntime(formula, sourceTransform);
                }
                else if (referencedByOldSheet) {
                    args.formulaSheetIndex.removeReference(oldSheetName, cellIndex);
                    appendSheetRenameSourceTransformForRuntime(formula, sourceTransform);
                }
                if (formula.directAggregate !== undefined) {
                    formula.directAggregate = renameDirectAggregateDescriptorSheetForRuntime(formula.directAggregate, oldSheetName, newSheetName);
                }
                if (previousOwnerSheetName !== ownerSheetName) {
                    args.formulaSheetIndex.appendOwner(ownerSheetName, cellIndex);
                }
                if (sourceChanged) {
                    args.formulaSheetIndex.appendReference(newSheetName, cellIndex);
                }
                else if (referencedByOldSheet) {
                    args.formulaSheetIndex.appendReference(newSheetName, cellIndex);
                }
                return;
            }
            const renamedMetadata = renameCompiledFormulaSheetReferenceMetadata(formula.compiled, oldSheetName, newSheetName);
            if (!renamedMetadata.sourceChanged) {
                if (referencedByOldSheet) {
                    args.formulaSheetIndex.removeReference(oldSheetName, cellIndex);
                    appendSheetRenameSourceTransformForRuntime(formula, sourceTransform);
                    if (formula.directAggregate !== undefined) {
                        formula.directAggregate = renameDirectAggregateDescriptorSheetForRuntime(formula.directAggregate, oldSheetName, newSheetName);
                    }
                    args.formulaSheetIndex.appendReference(newSheetName, cellIndex);
                }
                if (ownerSheetName === newSheetName) {
                    args.untrackFormulaSheetIndexes(cellIndex, oldSheetName, formula.compiled);
                    args.trackFormulaSheetIndexes(cellIndex, newSheetName, formula.compiled);
                }
                return;
            }
            const position = args.serviceArgs.state.workbook.getCellPosition(cellIndex);
            const ownerPosition = position
                ? {
                    sheetName: ownerSheetName,
                    row: position.row,
                    col: position.col,
                }
                : undefined;
            const canPreserveRuntime = formula.directLookup === undefined &&
                formula.directCriteria === undefined &&
                (canRewriteCompiledPreservingBindings(formula, renamedMetadata.compiled) ||
                    canRewriteCompiledPreservingDirectAggregate(formula, renamedMetadata.compiled) ||
                    canRewriteCompiledPreservingDirectScalar(formula, renamedMetadata.compiled));
            if (canPreserveRuntime) {
                const nextDirectAggregate = formula.directAggregate
                    ? renameDirectAggregateDescriptorSheetForRuntime(formula.directAggregate, oldSheetName, newSheetName)
                    : undefined;
                const nextDirectScalar = formula.directScalar === undefined
                    ? undefined
                    : buildDirectScalarDescriptor({
                        compiled: renamedMetadata.compiled,
                        ownerSheetName,
                        ownerSheetId: args.serviceArgs.state.workbook.cellStore.sheetIds[cellIndex],
                        workbook: args.serviceArgs.state.workbook,
                        ensureCellTracked: args.serviceArgs.ensureCellTracked,
                        ensureCellTrackedByCoords: args.serviceArgs.ensureCellTrackedByCoords,
                    });
                if (formula.directScalar === undefined || nextDirectScalar !== undefined) {
                    const plan = args.canRetainUnmanagedCompiledPlan(formula.planId, renamedMetadata.compiled, nextDirectScalar)
                        ? args.makeUnmanagedCompiledPlan(formula.source, renamedMetadata.compiled, formula.templateId)
                        : args.serviceArgs.compiledPlans.replace(formula.planId, formula.source, renamedMetadata.compiled, formula.templateId);
                    args.untrackFormulaSheetIndexes(cellIndex, previousOwnerSheetName, formula.compiled);
                    formula.compiled = plan.compiled;
                    formula.plan = plan;
                    formula.planId = plan.id;
                    formula.constants = plan.compiled.constants;
                    formula.constNumberLength = plan.compiled.constants.length;
                    formula.directAggregate = nextDirectAggregate;
                    formula.directScalar = nextDirectScalar;
                    args.serviceArgs.state.formulas.refreshTrackedMetadata(cellIndex);
                    appendSheetRenameSourceTransformForRuntime(formula, sourceTransform);
                    args.trackFormulaSheetIndexes(cellIndex, ownerSheetName, formula.compiled);
                    return;
                }
            }
            if (previousOwnerSheetName !== ownerSheetName) {
                args.untrackFormulaSheetIndexes(cellIndex, previousOwnerSheetName, formula.compiled);
            }
            const renamed = renameCompiledFormulaSheetReferences(formula.compiled, oldSheetName, newSheetName);
            const preserved = ownerPosition &&
                args.rewriteFormulaMetadataPreservingRuntimeNow(cellIndex, renamed.source, renamed.compiled, formula.templateId, ownerPosition);
            if (!preserved) {
                args.bindPreparedFormulaNow(cellIndex, ownerSheetName, renamed.source, renamed.compiled, formula.templateId);
            }
        };
        referencedCandidates?.forEach(rewriteCandidate);
        ownerCandidates?.forEach(rewriteCandidate);
        return formulaChangedCount;
    };
    return {
        deferCellFormulasForSheetRenameNow,
        rewriteCellFormulasForSheetRenameNow,
    };
}
//# sourceMappingURL=formula-binding-sheet-rename.js.map