import { calculationSettingsEqual, definedNameValuesEqual, normalizeWorkbookCalculationSettings } from '../engine-metadata-utils.js';
import { buildFormatClearOps, buildFormatPatchOps, buildStyleClearOps, buildStylePatchOps } from '../engine-range-format-ops.js';
import { hasEngineStructuralDeleteImpact, hasEngineStructuralInsertBoundaryPreparationImpact, hasEngineStructuralInsertImpact, } from './engine-structural-delete-impact.js';
import { buildSortRangeOps, buildSortTableOps } from './engine-sort-range.js';
import { buildApplyTableAutoFilterOps, buildClearWorksheetAutoFilterOps, buildSetWorksheetAutoFilterOps } from './engine-autofilter.js';
import { upsertNumericDefinedNameFast as upsertNumericDefinedNameFastPath } from './engine-numeric-defined-name-fast-path.js';
import { buildSetConditionalFormatOps, buildSetDataValidationOps, buildSetPivotTableOps, buildSetRangeProtectionOps, buildSetSheetProtectionOps, buildSetSortOps, } from './engine-workbook-metadata-ops.js';
import { normalizeEngineCommentThread, normalizeEngineHyperlink, normalizeEngineNote, workbookObjectRecordEqual, } from './engine-workbook-object-helpers.js';
import { buildDeleteChartOps, buildDeleteImageOps, buildDeleteShapeOps, buildDeleteTableOps, buildSetChartOps, buildSetImageOps, buildSetShapeOps, buildSetTableOps, } from './engine-workbook-object-metadata-ops.js';
import { SpreadsheetEngineRuntimeBase } from './engine-runtime-base.js';
import { rangesIntersect } from '../workbook-merge-records.js';
import { canonicalWorkbookRangeRef } from '../workbook-range-records.js';
import { normalizeDefinedName, } from '../workbook-store.js';
import { getRuntimeFormulaSource } from './runtime-formula-source.js';
export class SpreadsheetEngineWorkbookFacadeBase extends SpreadsheetEngineRuntimeBase {
    setRangeNumberFormat(range, format) {
        const ops = buildFormatPatchOps(this.workbook, range, format);
        this.executeLocalTransaction(ops);
    }
    clearRangeNumberFormat(range) {
        const ops = buildFormatClearOps(this.workbook, range);
        this.executeLocalTransaction(ops);
    }
    setRangeStyle(range, patch) {
        const ops = buildStylePatchOps(this.workbook, range, patch);
        this.executeLocalTransaction(ops);
    }
    clearRangeStyle(range, fields) {
        const ops = buildStyleClearOps(this.workbook, range, fields);
        this.executeLocalTransaction(ops);
    }
    getCellStyle(styleId) {
        return this.workbook.getCellStyle(styleId);
    }
    getCellNumberFormat(id) {
        return this.workbook.getCellNumberFormat(id);
    }
    setDefinedName(name, value) {
        const normalizedName = normalizeDefinedName(name);
        const previous = this.workbook.getDefinedName(normalizedName);
        const trimmedName = name.trim();
        if (previous?.name === trimmedName && definedNameValuesEqual(previous.value, value)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'upsertDefinedName', name: trimmedName, value }]);
    }
    collectDefinedNameDependentFormulaCells(name) {
        return this.runtime.binding.collectFormulaCellsForDefinedNamesNow([normalizeDefinedName(name)]);
    }
    upsertNumericDefinedNameFast(name, value, numericValue) {
        return upsertNumericDefinedNameFastPath({
            workbook: this.workbook,
            formulas: this.formulas,
            replicaState: this.replicaState,
            entityVersions: this.entityVersions,
            undoStack: this.undoStack,
            redoStack: this.redoStack,
            collectDependentFormulaCells: (normalizedName) => this.runtime.binding.collectFormulaCellsForDefinedNamesNow([normalizedName]),
            name,
            value,
            numericValue,
        });
    }
    deleteDefinedName(name) {
        if (!this.workbook.getDefinedName(name)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteDefinedName', name }]);
        return true;
    }
    getDefinedName(name, scopeSheetName) {
        return this.workbook.getDefinedName(name, scopeSheetName);
    }
    getDefinedNames() {
        return this.workbook.listDefinedNames();
    }
    setWorkbookMetadata(key, value) {
        const existing = this.workbook.getWorkbookProperty(key);
        if (existing?.value === value || (existing === undefined && value === null)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'setWorkbookMetadata', key, value }]);
    }
    getWorkbookMetadata(key) {
        return this.workbook.getWorkbookProperty(key);
    }
    getWorkbookMetadataEntries() {
        return this.workbook.listWorkbookProperties();
    }
    setCalculationSettings(settings) {
        const current = this.workbook.getCalculationSettings();
        const nextSettings = normalizeWorkbookCalculationSettings(settings, current);
        if (calculationSettingsEqual(current, nextSettings)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'setCalculationSettings', settings: nextSettings }]);
    }
    getCalculationSettings() {
        return this.workbook.getCalculationSettings();
    }
    getVolatileContext() {
        return this.workbook.getVolatileContext();
    }
    updateRowMetadata(sheetName, start, count, size, hidden) {
        const existing = this.workbook.getRowMetadata(sheetName, start, count);
        if (existing?.size === size && existing.hidden === hidden) {
            return;
        }
        if (existing === undefined && size === null && hidden === null) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'updateRowMetadata', sheetName, start, count, size, hidden }]);
    }
    getRowMetadata(sheetName) {
        return this.workbook.listRowMetadata(sheetName);
    }
    getRowAxisEntries(sheetName) {
        return this.workbook.listRowAxisEntries(sheetName);
    }
    insertRows(sheetName, start, count, options = {}) {
        if (count <= 0) {
            return;
        }
        const hasSemanticImpact = this.hasStructuralInsertImpact(sheetName, 'row', start, count);
        if (!hasSemanticImpact && !this.hasStructuralInsertBoundaryPreparationImpact(sheetName, 'row', start)) {
            return;
        }
        this.runtime.mutation.executeLocalSingleStructuralInsertNow({ kind: 'insertRows', sheetName, start, count }, undefined, hasSemanticImpact || options.recordHistory === true ? options : { ...options, recordHistory: false });
    }
    deleteRows(sheetName, start, count) {
        if (count <= 0 || !this.hasStructuralDeleteImpact(sheetName, 'row', start, count)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'deleteRows', sheetName, start, count }]);
    }
    moveRows(sheetName, start, count, target) {
        if (count <= 0 || start === target || !this.workbook.getSheet(sheetName)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'moveRows', sheetName, start, count, target }]);
    }
    updateColumnMetadata(sheetName, start, count, size, hidden) {
        const existing = this.workbook.getColumnMetadata(sheetName, start, count);
        if (existing?.size === size && existing.hidden === hidden) {
            return;
        }
        if (existing === undefined && size === null && hidden === null) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'updateColumnMetadata', sheetName, start, count, size, hidden }]);
    }
    getColumnMetadata(sheetName) {
        return this.workbook.listColumnMetadata(sheetName);
    }
    getColumnAxisEntries(sheetName) {
        return this.workbook.listColumnAxisEntries(sheetName);
    }
    insertColumns(sheetName, start, count, options = {}) {
        if (count <= 0) {
            return;
        }
        const hasSemanticImpact = this.hasStructuralInsertImpact(sheetName, 'column', start, count);
        if (!hasSemanticImpact && !this.hasStructuralInsertBoundaryPreparationImpact(sheetName, 'column', start)) {
            return;
        }
        this.runtime.mutation.executeLocalSingleStructuralInsertNow({ kind: 'insertColumns', sheetName, start, count }, undefined, hasSemanticImpact || options.recordHistory === true ? options : { ...options, recordHistory: false });
    }
    deleteColumns(sheetName, start, count) {
        if (count <= 0 || !this.hasStructuralDeleteImpact(sheetName, 'column', start, count)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'deleteColumns', sheetName, start, count }]);
    }
    moveColumns(sheetName, start, count, target) {
        if (count <= 0 || start === target || !this.workbook.getSheet(sheetName)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'moveColumns', sheetName, start, count, target }]);
    }
    setFreezePane(sheetName, rows, cols) {
        const existing = this.workbook.getFreezePane(sheetName);
        if (existing?.rows === rows && existing.cols === cols) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'setFreezePane', sheetName, rows, cols }]);
    }
    clearFreezePane(sheetName) {
        if (!this.workbook.getFreezePane(sheetName)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'clearFreezePane', sheetName }]);
        return true;
    }
    getFreezePane(sheetName) {
        return this.workbook.getFreezePane(sheetName);
    }
    mergeCells(range) {
        const normalized = canonicalWorkbookRangeRef(range);
        const existing = this.workbook.getMergeRangeByRange(normalized);
        if (existing) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'mergeCells', range: normalized }]);
    }
    unmergeCells(range) {
        const overlaps = this.workbook.listMergeRanges(range.sheetName).filter((record) => rangesIntersect(record, range));
        if (overlaps.length === 0) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'unmergeCells', range: canonicalWorkbookRangeRef(range) }]);
        return true;
    }
    getMergeRange(sheetName, address) {
        return this.workbook.getMergeRange(sheetName, address);
    }
    getMergeRangeByRange(range) {
        return this.workbook.getMergeRangeByRange(range);
    }
    listMergeRanges(sheetName) {
        return this.workbook.listMergeRanges(sheetName);
    }
    setSheetProtection(protection) {
        this.executeLocalTransaction(buildSetSheetProtectionOps(this.workbook, protection) ?? []);
    }
    clearSheetProtection(sheetName) {
        if (!this.workbook.getSheetProtection(sheetName)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'clearSheetProtection', sheetName }]);
        return true;
    }
    getSheetProtection(sheetName) {
        return this.workbook.getSheetProtection(sheetName);
    }
    setFilter(sheetName, range) {
        const normalizedRange = range.sheetName === sheetName ? range : { ...range, sheetName };
        const ops = buildSetWorksheetAutoFilterOps(this.exportSnapshot(), normalizedRange);
        this.executeLocalTransaction(ops);
        if (ops.some((op) => op.kind === 'updateRowMetadata')) {
            this.recalculateNow();
        }
    }
    applyTableAutoFilter(sheetName, tableName, criteria) {
        const ops = buildApplyTableAutoFilterOps(this.exportSnapshot(), sheetName, tableName, criteria);
        if (ops.length === 0) {
            return false;
        }
        this.executeLocalTransaction(ops);
        if (ops.some((op) => op.kind === 'updateRowMetadata')) {
            this.recalculateNow();
        }
        return true;
    }
    clearFilter(sheetName, range) {
        if (!this.workbook.getFilter(sheetName, range)) {
            return false;
        }
        const ops = buildClearWorksheetAutoFilterOps(this.exportSnapshot(), range);
        this.executeLocalTransaction(ops);
        if (ops.some((op) => op.kind === 'updateRowMetadata')) {
            this.recalculateNow();
        }
        return true;
    }
    getFilters(sheetName) {
        return this.workbook.listFilters(sheetName);
    }
    setSort(sheetName, range, keys) {
        this.executeLocalTransaction(buildSetSortOps(this.workbook, sheetName, range, keys) ?? []);
    }
    sortRange(sheetName, range, keys, options = {}) {
        const ops = buildSortRangeOps(this.exportSnapshot(), sheetName, range, keys, options);
        if (ops.length === 0) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    sortTable(sheetName, tableName, keys) {
        const ops = buildSortTableOps(this.exportSnapshot(), sheetName, tableName, keys);
        if (ops.length === 0) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    clearSort(sheetName, range) {
        if (!this.workbook.getSort(sheetName, range)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'clearSort', sheetName, range: { ...range } }]);
        return true;
    }
    getSorts(sheetName) {
        return this.workbook.listSorts(sheetName);
    }
    setDataValidation(validation) {
        this.executeLocalTransaction(buildSetDataValidationOps(this.workbook, validation) ?? []);
    }
    clearDataValidation(sheetName, range) {
        if (!this.workbook.getDataValidation(sheetName, range)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'clearDataValidation', sheetName, range: { ...range } }]);
        return true;
    }
    getDataValidation(sheetName, range) {
        return this.workbook.getDataValidation(sheetName, range);
    }
    getDataValidations(sheetName) {
        return this.workbook.listDataValidations(sheetName);
    }
    setConditionalFormat(format) {
        this.executeLocalTransaction(buildSetConditionalFormatOps(this.workbook, format) ?? []);
    }
    deleteConditionalFormat(id) {
        const existing = this.workbook.getConditionalFormat(id);
        if (!existing) {
            return false;
        }
        this.executeLocalTransaction([
            {
                kind: 'deleteConditionalFormat',
                id: existing.id,
                sheetName: existing.range.sheetName,
            },
        ]);
        return true;
    }
    getConditionalFormat(id) {
        return this.workbook.getConditionalFormat(id);
    }
    getConditionalFormats(sheetName) {
        return this.workbook.listConditionalFormats(sheetName);
    }
    setRangeProtection(protection) {
        this.executeLocalTransaction(buildSetRangeProtectionOps(this.workbook, protection) ?? []);
    }
    deleteRangeProtection(id) {
        const existing = this.workbook.getRangeProtection(id);
        if (!existing) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteRangeProtection', id: existing.id, sheetName: existing.range.sheetName }]);
        return true;
    }
    getRangeProtection(id) {
        return this.workbook.getRangeProtection(id);
    }
    getRangeProtections(sheetName) {
        return this.workbook.listRangeProtections(sheetName);
    }
    setCommentThread(thread) {
        const normalized = normalizeEngineCommentThread(thread);
        const existing = this.workbook.getCommentThread(normalized.sheetName, normalized.address);
        if (workbookObjectRecordEqual(existing, normalized)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'upsertCommentThread', thread: normalized }]);
    }
    deleteCommentThread(sheetName, address) {
        if (!this.workbook.getCommentThread(sheetName, address)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteCommentThread', sheetName, address }]);
        return true;
    }
    getCommentThread(sheetName, address) {
        return this.workbook.getCommentThread(sheetName, address);
    }
    getCommentThreads(sheetName) {
        return this.workbook.listCommentThreads(sheetName);
    }
    setNote(note) {
        const normalized = normalizeEngineNote(note);
        const existing = this.workbook.getNote(normalized.sheetName, normalized.address);
        if (workbookObjectRecordEqual(existing, normalized)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'upsertNote', note: normalized }]);
    }
    deleteNote(sheetName, address) {
        if (!this.workbook.getNote(sheetName, address)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteNote', sheetName, address }]);
        return true;
    }
    getNote(sheetName, address) {
        return this.workbook.getNote(sheetName, address);
    }
    getNotes(sheetName) {
        return this.workbook.listNotes(sheetName);
    }
    setHyperlink(hyperlink) {
        const normalized = normalizeEngineHyperlink(hyperlink);
        const existing = this.workbook.getHyperlink(normalized.sheetName, normalized.address);
        if (workbookObjectRecordEqual(existing, normalized)) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'upsertHyperlink', hyperlink: normalized }]);
    }
    deleteHyperlink(sheetName, address) {
        if (!this.workbook.getHyperlink(sheetName, address)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteHyperlink', sheetName, address }]);
        return true;
    }
    getHyperlink(sheetName, address) {
        return this.workbook.getHyperlink(sheetName, address);
    }
    getHyperlinks(sheetName) {
        return this.workbook.listHyperlinks(sheetName);
    }
    setTable(table) {
        this.executeLocalTransaction(buildSetTableOps(this.workbook, table));
    }
    deleteTable(name) {
        const ops = buildDeleteTableOps(this.workbook, name);
        if (!ops) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    getTable(name) {
        return this.workbook.getTable(name);
    }
    getTables() {
        return this.workbook.listTables();
    }
    setSpillRange(sheetName, address, rows, cols) {
        const existing = this.workbook.getSpill(sheetName, address);
        if (existing?.rows === rows && existing.cols === cols) {
            return;
        }
        this.executeLocalTransaction([{ kind: 'upsertSpillRange', sheetName, address, rows, cols }]);
    }
    deleteSpillRange(sheetName, address) {
        if (!this.workbook.getSpill(sheetName, address)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deleteSpillRange', sheetName, address }]);
        return true;
    }
    getSpillRanges() {
        return this.workbook.listSpills();
    }
    setPivotTable(sheetName, address, definition) {
        this.executeLocalTransaction(buildSetPivotTableOps(sheetName, address, definition));
    }
    deletePivotTable(sheetName, address) {
        if (!this.workbook.getPivot(sheetName, address)) {
            return false;
        }
        this.executeLocalTransaction([{ kind: 'deletePivotTable', sheetName, address }]);
        return true;
    }
    getPivotTable(sheetName, address) {
        return this.workbook.getPivot(sheetName, address);
    }
    getPivotTables() {
        return this.workbook.listPivots();
    }
    setChart(chart) {
        this.executeLocalTransaction(buildSetChartOps(this.workbook, chart));
    }
    deleteChart(id) {
        const ops = buildDeleteChartOps(this.workbook, id);
        if (!ops) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    getChart(id) {
        return this.workbook.getChart(id);
    }
    getCharts() {
        return this.workbook.listCharts();
    }
    setImage(image) {
        this.executeLocalTransaction(buildSetImageOps(this.workbook, image));
    }
    deleteImage(id) {
        const ops = buildDeleteImageOps(this.workbook, id);
        if (!ops) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    getImage(id) {
        return this.workbook.getImage(id);
    }
    getImages() {
        return this.workbook.listImages();
    }
    setShape(shape) {
        this.executeLocalTransaction(buildSetShapeOps(this.workbook, shape));
    }
    deleteShape(id) {
        const ops = buildDeleteShapeOps(this.workbook, id);
        if (!ops) {
            return false;
        }
        this.executeLocalTransaction(ops);
        return true;
    }
    getShape(id) {
        return this.workbook.getShape(id);
    }
    getShapes() {
        return this.workbook.listShapes();
    }
    hasStructuralDeleteImpact(sheetName, axis, start, count) {
        return hasEngineStructuralDeleteImpact({
            workbook: this.workbook,
            getCellByIndex: (cellIndex) => this.getCellByIndex(cellIndex),
            getFormulaSourceByIndex: (cellIndex) => {
                const formula = this.formulas.get(cellIndex);
                return formula
                    ? getRuntimeFormulaSource(formula, this.runtime.binding.getFormulaFamilyStructuralSourceTransformNow(cellIndex))
                    : undefined;
            },
            sheetName,
            axis,
            start,
            count,
        });
    }
    hasStructuralInsertImpact(sheetName, axis, start, count) {
        return hasEngineStructuralInsertImpact({
            workbook: this.workbook,
            getCellByIndex: (cellIndex) => this.getCellByIndex(cellIndex),
            getFormulaSourceByIndex: (cellIndex) => {
                const formula = this.formulas.get(cellIndex);
                return formula
                    ? getRuntimeFormulaSource(formula, this.runtime.binding.getFormulaFamilyStructuralSourceTransformNow(cellIndex))
                    : undefined;
            },
            sheetName,
            axis,
            start,
            count,
        });
    }
    hasStructuralInsertBoundaryPreparationImpact(sheetName, axis, start) {
        return hasEngineStructuralInsertBoundaryPreparationImpact({
            workbook: this.workbook,
            sheetName,
            axis,
            start,
        });
    }
}
//# sourceMappingURL=engine-workbook-facade-base.js.map