import { parseCellAddress, parseRangeAddress } from '@bilig/formula';
import { ErrorCode } from '@bilig/protocol';
export function buildDirectScalarOperand(args) {
    if (args.node.kind === 'NumberLiteral') {
        return { kind: 'literal-number', value: args.node.value };
    }
    if (args.node.kind === 'CellRef') {
        const translated = args.nextTranslatedCellRef?.();
        const sheetName = translated?.sheetName ?? args.node.sheetName ?? args.ownerSheetName;
        const sheetId = sheetName === args.ownerSheetName ? args.ownerSheetId : args.workbook.getSheet(sheetName)?.id;
        if (sheetId === undefined) {
            return {
                kind: 'error',
                code: ErrorCode.Ref,
            };
        }
        if (translated?.row !== undefined && translated.col !== undefined) {
            const existingCellIndex = args.workbook.getFreshCellIndexAt?.(sheetId, translated.row, translated.col) ??
                args.workbook.getCellIndexAt?.(sheetId, translated.row, translated.col);
            return {
                kind: 'cell',
                cellIndex: existingCellIndex ?? args.ensureCellTrackedByCoords(sheetId, translated.row, translated.col),
            };
        }
        let parsed;
        try {
            parsed = parseCellAddress(translated?.address ?? args.node.ref, sheetName);
        }
        catch {
            return {
                kind: 'error',
                code: ErrorCode.Ref,
            };
        }
        return {
            kind: 'cell',
            cellIndex: args.ensureCellTracked(parsed.sheetName ?? sheetName, parsed.text),
        };
    }
    return undefined;
}
export function unwrapDirectScalarBinaryNode(node) {
    if (node.kind === 'BinaryExpr' &&
        node.operator === '+' &&
        node.right.kind === 'NumberLiteral' &&
        Number.isFinite(node.right.value) &&
        node.left.kind === 'BinaryExpr' &&
        (node.left.operator === '+' || node.left.operator === '-' || node.left.operator === '*' || node.left.operator === '/')) {
        return {
            node: node.left,
            resultOffset: node.right.value,
        };
    }
    return {
        node,
        resultOffset: undefined,
    };
}
export function tryParseDependencyRangeAddress(address, currentSheetName) {
    try {
        return parseRangeAddress(address, currentSheetName);
    }
    catch {
        return undefined;
    }
}
export function tryParseDependencyCellAddress(address, currentSheetName) {
    try {
        return parseCellAddress(address, currentSheetName);
    }
    catch {
        return undefined;
    }
}
export function buildDirectScalarDescriptor(args) {
    if (args.compiled.symbolicNames.length > 0 || args.compiled.symbolicTables.length > 0 || args.compiled.symbolicSpills.length > 0) {
        return undefined;
    }
    if (args.compiled.astMatchesSource === false) {
        const translated = tryBuildTranslatedDirectScalarDescriptor(args);
        if (translated) {
            return translated;
        }
    }
    let translatedCellRefIndex = 0;
    const nextTranslatedCellRef = args.compiled.astMatchesSource === false
        ? () => {
            const parsed = args.compiled.parsedSymbolicRefs?.[translatedCellRefIndex];
            const address = parsed?.address ?? args.compiled.symbolicRefs[translatedCellRefIndex];
            translatedCellRefIndex += 1;
            return address ? { sheetName: parsed?.sheetName, address, row: parsed?.row, col: parsed?.col } : undefined;
        }
        : undefined;
    const unwrapped = unwrapDirectScalarBinaryNode(args.compiled.optimizedAst);
    const node = unwrapped.node;
    if (node.kind === 'BinaryExpr' && (node.operator === '+' || node.operator === '-' || node.operator === '*' || node.operator === '/')) {
        const left = buildDirectScalarOperand({
            node: node.left,
            ownerSheetName: args.ownerSheetName,
            ownerSheetId: args.ownerSheetId,
            workbook: args.workbook,
            ensureCellTracked: args.ensureCellTracked,
            ensureCellTrackedByCoords: args.ensureCellTrackedByCoords,
            ...(nextTranslatedCellRef ? { nextTranslatedCellRef } : {}),
        });
        const right = buildDirectScalarOperand({
            node: node.right,
            ownerSheetName: args.ownerSheetName,
            ownerSheetId: args.ownerSheetId,
            workbook: args.workbook,
            ensureCellTracked: args.ensureCellTracked,
            ensureCellTrackedByCoords: args.ensureCellTrackedByCoords,
            ...(nextTranslatedCellRef ? { nextTranslatedCellRef } : {}),
        });
        if (left && right) {
            return withDirectScalarDeltaInputCellIndex({
                kind: 'binary',
                operator: node.operator,
                left,
                right,
                ...(unwrapped.resultOffset !== undefined ? { resultOffset: unwrapped.resultOffset } : {}),
            });
        }
    }
    if (node.kind === 'CallExpr' && node.callee.trim().toUpperCase() === 'ABS' && node.args.length === 1) {
        const operand = buildDirectScalarOperand({
            node: node.args[0],
            ownerSheetName: args.ownerSheetName,
            ownerSheetId: args.ownerSheetId,
            workbook: args.workbook,
            ensureCellTracked: args.ensureCellTracked,
            ensureCellTrackedByCoords: args.ensureCellTrackedByCoords,
            ...(nextTranslatedCellRef ? { nextTranslatedCellRef } : {}),
        });
        if (operand) {
            return {
                kind: 'abs',
                operand,
            };
        }
    }
    return undefined;
}
function tryBuildTranslatedDirectScalarDescriptor(args) {
    const parsedRefs = args.compiled.parsedSymbolicRefs;
    if (parsedRefs === undefined) {
        return undefined;
    }
    let translatedCellRefIndex = 0;
    const unwrapped = unwrapDirectScalarBinaryNode(args.compiled.optimizedAst);
    const node = unwrapped.node;
    if (node.kind === 'BinaryExpr' && (node.operator === '+' || node.operator === '-' || node.operator === '*' || node.operator === '/')) {
        const left = buildTranslatedDirectScalarOperand(args, node.left, parsedRefs[translatedCellRefIndex]);
        if (node.left.kind === 'CellRef') {
            translatedCellRefIndex += 1;
        }
        const right = buildTranslatedDirectScalarOperand(args, node.right, parsedRefs[translatedCellRefIndex]);
        if (node.right.kind === 'CellRef') {
            translatedCellRefIndex += 1;
        }
        if (left && right && translatedCellRefIndex === parsedRefs.length) {
            return withDirectScalarDeltaInputCellIndex({
                kind: 'binary',
                operator: node.operator,
                left,
                right,
                ...(unwrapped.resultOffset !== undefined ? { resultOffset: unwrapped.resultOffset } : {}),
            });
        }
        return undefined;
    }
    if (node.kind === 'CallExpr' && node.callee.trim().toUpperCase() === 'ABS' && node.args.length === 1) {
        const operandNode = node.args[0];
        const operand = buildTranslatedDirectScalarOperand(args, operandNode, parsedRefs[translatedCellRefIndex]);
        if (operandNode.kind === 'CellRef') {
            translatedCellRefIndex += 1;
        }
        if (operand && translatedCellRefIndex === parsedRefs.length) {
            return {
                kind: 'abs',
                operand,
            };
        }
    }
    return undefined;
}
function buildTranslatedDirectScalarOperand(args, node, parsed) {
    if (node.kind === 'NumberLiteral') {
        return { kind: 'literal-number', value: node.value };
    }
    if (node.kind !== 'CellRef') {
        return undefined;
    }
    if (parsed === undefined || parsed.row === undefined || parsed.col === undefined) {
        return undefined;
    }
    const sheetName = parsed.sheetName ?? node.sheetName ?? args.ownerSheetName;
    const sheetId = sheetName === args.ownerSheetName ? args.ownerSheetId : args.workbook.getSheet(sheetName)?.id;
    if (sheetId === undefined) {
        return {
            kind: 'error',
            code: ErrorCode.Ref,
        };
    }
    const existingCellIndex = args.workbook.getFreshCellIndexAt?.(sheetId, parsed.row, parsed.col) ?? args.workbook.getCellIndexAt?.(sheetId, parsed.row, parsed.col);
    return {
        kind: 'cell',
        cellIndex: existingCellIndex ?? args.ensureCellTrackedByCoords(sheetId, parsed.row, parsed.col),
    };
}
function withDirectScalarDeltaInputCellIndex(descriptor) {
    if (descriptor.kind !== 'binary') {
        return descriptor;
    }
    const cellIndex = directScalarDeltaInputCellIndex(descriptor);
    if (cellIndex !== undefined) {
        descriptor.deltaInputCellIndex = cellIndex;
    }
    return descriptor;
}
function directScalarDeltaInputCellIndex(directScalar) {
    const left = directScalar.left;
    const right = directScalar.right;
    if (left.kind === 'cell' && right.kind === 'literal-number' && (directScalar.operator === '+' || directScalar.operator === '-')) {
        return left.cellIndex;
    }
    if (directScalar.operator === '+' && right.kind === 'cell' && left.kind === 'literal-number') {
        return right.cellIndex;
    }
    return undefined;
}
//# sourceMappingURL=formula-binding-direct-scalar.js.map