import { ValueTag } from '@bilig/protocol';
import { parseCellAddress, rewriteFormulaForStructuralTransform } from '@bilig/formula';
import { drawingArtifactsTouchStructuralDelete } from './services/structure-drawing-artifact-rewrite.js';
import { drawingChartPackageArtifactsTouchStructuralDelete, preservedChartPackageArtifactsTouchStructuralDelete, } from './services/structure-chart-artifact-rewrite.js';
import { preservedSheetMetadataTouchesStructuralDelete } from './services/structure-preserved-sheet-metadata-rewrite.js';
import { isQualifiedRefErrorFormulaSource, rewriteTableForStructuralTransform, workbookTableRecordsEqual, } from './services/structure-metadata-rewrite.js';
function formulaWouldRewriteForStructuralTransform(formula, sheetName, axis, start, count, kind) {
    if (isQualifiedRefErrorFormulaSource(formula)) {
        return false;
    }
    const hasLeadingEquals = formula.startsWith('=');
    const source = hasLeadingEquals ? formula.slice(1) : formula;
    const rewritten = rewriteFormulaForStructuralTransform(source, sheetName, sheetName, {
        kind,
        axis,
        start,
        count,
    });
    return (hasLeadingEquals ? `=${rewritten}` : rewritten) !== formula;
}
function formulaWouldRewriteForDelete(formula, sheetName, axis, start, count) {
    return formulaWouldRewriteForStructuralTransform(formula, sheetName, axis, start, count, 'delete');
}
function formulaWouldRewriteForInsert(formula, sheetName, axis, start, count) {
    return formulaWouldRewriteForStructuralTransform(formula, sheetName, axis, start, count, 'insert');
}
function cellHasSemanticDeleteImpact(args) {
    const snapshot = args.getCellByIndex(args.cellIndex);
    if (snapshot.formula !== undefined) {
        return true;
    }
    if (args.workbook.getCellFormat(args.cellIndex) !== undefined) {
        return true;
    }
    if ((snapshot.flags & 256 /* CellFlags.AuthoredBlank */) !== 0) {
        return true;
    }
    return snapshot.value.tag === ValueTag.Number || snapshot.value.tag === ValueTag.Boolean || snapshot.value.tag === ValueTag.String;
}
function hasFormulaReferenceAtOrAfter(args) {
    let found = false;
    for (const sheet of args.workbook.sheetsByName.values()) {
        if (found) {
            break;
        }
        sheet.grid.forEachCell((cellIndex) => {
            if (found) {
                return;
            }
            const formulaId = args.workbook.cellStore.formulaIds[cellIndex] ?? 0;
            if (formulaId === 0) {
                return;
            }
            const formula = args.getFormulaSourceByIndex?.(cellIndex) ?? args.getCellByIndex(cellIndex).formula;
            if (formula && formulaWouldRewriteForStructuralTransform(formula, args.sheetName, args.axis, args.start, args.count, args.kind)) {
                found = true;
            }
        });
    }
    return found;
}
function definedNameTouchesAxisDelete(value, sheetName, axis, start, count) {
    if (typeof value === 'string') {
        return formulaWouldRewriteForDelete(value, sheetName, axis, start, count);
    }
    if (value === null || typeof value !== 'object') {
        return false;
    }
    switch (value.kind) {
        case 'scalar':
        case 'structured-ref':
            return false;
        case 'formula':
            return formulaWouldRewriteForDelete(value.formula, sheetName, axis, start, count);
        case 'cell-ref': {
            if (value.sheetName !== sheetName) {
                return false;
            }
            const parsed = parseCellAddress(value.address, value.sheetName);
            return axis === 'row' ? parsed.row >= start : parsed.col >= start;
        }
        case 'range-ref': {
            if (value.sheetName !== sheetName) {
                return false;
            }
            const end = parseCellAddress(value.endAddress, value.sheetName);
            return axis === 'row' ? end.row >= start : end.col >= start;
        }
    }
}
function rangeTouchesAxisDelete(range, axis, start) {
    const end = parseCellAddress(range.endAddress, range.sheetName);
    return axis === 'row' ? end.row >= start : end.col >= start;
}
function addressShiftsAfterAxisDelete(sheetName, address, axis, start, count) {
    const parsed = parseCellAddress(address, sheetName);
    return axis === 'row' ? parsed.row >= start + count : parsed.col >= start + count;
}
function sortTouchesAxisTransform(sort, axis, start, count, kind) {
    if (rangeTouchesAxisDelete(sort.range, axis, start)) {
        return true;
    }
    return sort.keys.some((key) => kind === 'insert'
        ? addressTouchesAxisDelete(sort.sheetName, key.keyAddress, axis, start)
        : addressShiftsAfterAxisDelete(sort.sheetName, key.keyAddress, axis, start, count));
}
function dataValidationTouchesAxisDelete(validation, sheetName, axis, start, count) {
    if (validation.rule.kind !== 'list' || !validation.rule.source) {
        return false;
    }
    const source = validation.rule.source;
    switch (source.kind) {
        case 'cell-ref':
            return source.sheetName === sheetName && addressTouchesAxisDelete(sheetName, source.address, axis, start);
        case 'range-ref':
            return source.sheetName === sheetName && rangeTouchesAxisDelete(source, axis, start);
        case 'formula':
            return formulaWouldRewriteForDelete(source.formula, sheetName, axis, start, count);
        case 'named-range':
        case 'structured-ref':
            return false;
    }
}
function tableTouchesAxisDelete(table, sheetName, axis, start, count) {
    if (table.sheetName !== sheetName) {
        return false;
    }
    const rewrite = rewriteTableForStructuralTransform(table, { kind: 'delete', axis, start, count });
    return (!rewrite ||
        !workbookTableRecordsEqual(table, rewrite.table) ||
        rewrite.headerCellWrites.length > 0 ||
        rewrite.deletedColumnNames.length > 0);
}
function addressTouchesAxisDelete(sheetName, address, axis, start) {
    const parsed = parseCellAddress(address, sheetName);
    return axis === 'row' ? parsed.row >= start : parsed.col >= start;
}
function definedNameTouchesAxisInsert(value, sheetName, axis, start, count) {
    if (typeof value === 'string') {
        return formulaWouldRewriteForInsert(value, sheetName, axis, start, count);
    }
    if (value === null || typeof value !== 'object') {
        return false;
    }
    switch (value.kind) {
        case 'scalar':
        case 'structured-ref':
            return false;
        case 'formula':
            return formulaWouldRewriteForInsert(value.formula, sheetName, axis, start, count);
        case 'cell-ref': {
            if (value.sheetName !== sheetName) {
                return false;
            }
            const parsed = parseCellAddress(value.address, value.sheetName);
            return axis === 'row' ? parsed.row >= start : parsed.col >= start;
        }
        case 'range-ref': {
            if (value.sheetName !== sheetName) {
                return false;
            }
            const end = parseCellAddress(value.endAddress, value.sheetName);
            return axis === 'row' ? end.row >= start : end.col >= start;
        }
    }
}
function dataValidationTouchesAxisInsert(validation, sheetName, axis, start, count) {
    if (validation.rule.kind !== 'list' || !validation.rule.source) {
        return false;
    }
    const source = validation.rule.source;
    switch (source.kind) {
        case 'cell-ref':
            return source.sheetName === sheetName && addressTouchesAxisDelete(sheetName, source.address, axis, start);
        case 'range-ref':
            return source.sheetName === sheetName && rangeTouchesAxisDelete(source, axis, start);
        case 'formula':
            return formulaWouldRewriteForInsert(source.formula, sheetName, axis, start, count);
        case 'named-range':
        case 'structured-ref':
            return false;
    }
}
export function hasEngineStructuralInsertImpact(args) {
    const sheet = args.workbook.getSheet(args.sheetName);
    if (!sheet) {
        return false;
    }
    if (sheet.grid.someCellInAxisScope(args.axis, { start: args.start }, (cellIndex) => cellHasSemanticDeleteImpact({
        workbook: args.workbook,
        getCellByIndex: args.getCellByIndex,
        cellIndex,
    }))) {
        return true;
    }
    const axisEntries = args.axis === 'row' ? args.workbook.listRowAxisEntries(args.sheetName) : args.workbook.listColumnAxisEntries(args.sheetName);
    if (axisEntries.some((entry) => entry.index >= args.start)) {
        return true;
    }
    const axisMetadata = args.axis === 'row' ? args.workbook.listRowMetadata(args.sheetName) : args.workbook.listColumnMetadata(args.sheetName);
    if (axisMetadata.some((record) => record.start + record.count - 1 >= args.start)) {
        return true;
    }
    if (args.workbook.listStyleRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listFormatRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listMergeRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record, args.axis, args.start))) {
        return true;
    }
    const freezePane = args.workbook.getFreezePane(args.sheetName);
    if (freezePane && (args.axis === 'row' ? freezePane.rows > args.start : freezePane.cols > args.start)) {
        return true;
    }
    if (args.workbook.listFilters(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listSorts(args.sheetName).some((record) => sortTouchesAxisTransform(record, args.axis, args.start, args.count, 'insert'))) {
        return true;
    }
    if (args.workbook.listDataValidations(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listConditionalFormats(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listRangeProtections(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listCommentThreads(args.sheetName)
        .some((record) => addressTouchesAxisDelete(args.sheetName, record.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listNotes(args.sheetName)
        .some((record) => addressTouchesAxisDelete(args.sheetName, record.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listTables()
        .some((table) => table.sheetName === args.sheetName &&
        rangeTouchesAxisDelete({ sheetName: args.sheetName, startAddress: table.startAddress, endAddress: table.endAddress }, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listSpills()
        .some((spill) => spill.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, spill.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listPivots()
        .some((pivot) => (pivot.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, pivot.address, args.axis, args.start)) ||
        (pivot.source?.sheetName === args.sheetName && rangeTouchesAxisDelete(pivot.source, args.axis, args.start)))) {
        return true;
    }
    if (args.workbook
        .listCharts()
        .some((chart) => (chart.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, chart.address, args.axis, args.start)) ||
        (chart.source.sheetName === args.sheetName && rangeTouchesAxisDelete(chart.source, args.axis, args.start)))) {
        return true;
    }
    if (args.workbook
        .listImages()
        .some((image) => image.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, image.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listShapes()
        .some((shape) => shape.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, shape.address, args.axis, args.start))) {
        return true;
    }
    if (preservedSheetMetadataTouchesStructuralDelete(args.workbook.metadata.preservedSheetMetadata.get(args.sheetName), args.axis, args.start)) {
        return true;
    }
    if (drawingArtifactsTouchStructuralDelete(args.workbook, args.sheetName)) {
        return true;
    }
    if (drawingChartPackageArtifactsTouchStructuralDelete(args.workbook, args.sheetName, args.axis, args.start, args.count)) {
        return true;
    }
    if (preservedChartPackageArtifactsTouchStructuralDelete(args.workbook.metadata.preservedWorkbookMetadata, args.sheetName, args.axis, args.start, args.count)) {
        return true;
    }
    if (args.workbook
        .listDefinedNames()
        .some((definedName) => definedNameTouchesAxisInsert(definedName.value, args.sheetName, args.axis, args.start, args.count))) {
        return true;
    }
    for (const candidateSheet of args.workbook.sheetsByName.values()) {
        if (args.workbook
            .listDataValidations(candidateSheet.name)
            .some((validation) => dataValidationTouchesAxisInsert(validation, args.sheetName, args.axis, args.start, args.count))) {
            return true;
        }
    }
    return hasFormulaReferenceAtOrAfter({ ...args, kind: 'insert' });
}
export function hasEngineStructuralInsertBoundaryPreparationImpact(args) {
    const sheet = args.workbook.getSheet(args.sheetName);
    return !!sheet && args.start > 0 && sheet.grid.someCellInAxisScope(args.axis, { start: args.start - 1, end: args.start }, () => true);
}
export function hasEngineStructuralDeleteImpact(args) {
    const sheet = args.workbook.getSheet(args.sheetName);
    if (!sheet) {
        return false;
    }
    if (sheet.grid.someCellInAxisScope(args.axis, { start: args.start }, (cellIndex) => cellHasSemanticDeleteImpact({
        workbook: args.workbook,
        getCellByIndex: args.getCellByIndex,
        cellIndex,
    }))) {
        return true;
    }
    const axisEntries = args.axis === 'row' ? args.workbook.listRowAxisEntries(args.sheetName) : args.workbook.listColumnAxisEntries(args.sheetName);
    if (axisEntries.some((entry) => entry.index >= args.start)) {
        return true;
    }
    const axisMetadata = args.axis === 'row' ? args.workbook.listRowMetadata(args.sheetName) : args.workbook.listColumnMetadata(args.sheetName);
    if (axisMetadata.some((record) => record.start + record.count - 1 >= args.start)) {
        return true;
    }
    if (args.workbook.listStyleRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listFormatRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listMergeRanges(args.sheetName).some((record) => rangeTouchesAxisDelete(record, args.axis, args.start))) {
        return true;
    }
    const freezePane = args.workbook.getFreezePane(args.sheetName);
    if (freezePane && (args.axis === 'row' ? freezePane.rows > args.start : freezePane.cols > args.start)) {
        return true;
    }
    if (args.workbook.listFilters(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listSorts(args.sheetName).some((record) => sortTouchesAxisTransform(record, args.axis, args.start, args.count, 'delete'))) {
        return true;
    }
    if (args.workbook.listDataValidations(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listConditionalFormats(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listRangeProtections(args.sheetName).some((record) => rangeTouchesAxisDelete(record.range, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listCommentThreads(args.sheetName)
        .some((record) => addressTouchesAxisDelete(args.sheetName, record.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listNotes(args.sheetName)
        .some((record) => addressTouchesAxisDelete(args.sheetName, record.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook.listTables().some((table) => tableTouchesAxisDelete(table, args.sheetName, args.axis, args.start, args.count))) {
        return true;
    }
    if (args.workbook
        .listSpills()
        .some((spill) => spill.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, spill.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listPivots()
        .some((pivot) => (pivot.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, pivot.address, args.axis, args.start)) ||
        (pivot.source?.sheetName === args.sheetName && rangeTouchesAxisDelete(pivot.source, args.axis, args.start)))) {
        return true;
    }
    if (args.workbook
        .listCharts()
        .some((chart) => (chart.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, chart.address, args.axis, args.start)) ||
        (chart.source.sheetName === args.sheetName && rangeTouchesAxisDelete(chart.source, args.axis, args.start)))) {
        return true;
    }
    if (args.workbook
        .listImages()
        .some((image) => image.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, image.address, args.axis, args.start))) {
        return true;
    }
    if (args.workbook
        .listShapes()
        .some((shape) => shape.sheetName === args.sheetName && addressTouchesAxisDelete(args.sheetName, shape.address, args.axis, args.start))) {
        return true;
    }
    if (preservedSheetMetadataTouchesStructuralDelete(args.workbook.metadata.preservedSheetMetadata.get(args.sheetName), args.axis, args.start)) {
        return true;
    }
    if (drawingArtifactsTouchStructuralDelete(args.workbook, args.sheetName)) {
        return true;
    }
    if (drawingChartPackageArtifactsTouchStructuralDelete(args.workbook, args.sheetName, args.axis, args.start, args.count)) {
        return true;
    }
    if (preservedChartPackageArtifactsTouchStructuralDelete(args.workbook.metadata.preservedWorkbookMetadata, args.sheetName, args.axis, args.start, args.count)) {
        return true;
    }
    if (args.workbook
        .listDefinedNames()
        .some((definedName) => definedNameTouchesAxisDelete(definedName.value, args.sheetName, args.axis, args.start, args.count))) {
        return true;
    }
    for (const candidateSheet of args.workbook.sheetsByName.values()) {
        if (args.workbook
            .listDataValidations(candidateSheet.name)
            .some((validation) => dataValidationTouchesAxisDelete(validation, args.sheetName, args.axis, args.start, args.count))) {
            return true;
        }
    }
    return hasFormulaReferenceAtOrAfter({ ...args, kind: 'delete' });
}
//# sourceMappingURL=engine-structural-delete-impact.js.map