"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get buildSummaryFormula () {
        return buildSummaryFormula;
    },
    get colIndexToLetter () {
        return colIndexToLetter;
    },
    get colLetterToIndex () {
        return colLetterToIndex;
    },
    get isFormulaValue () {
        return isFormulaValue;
    },
    get normalizeFormula () {
        return normalizeFormula;
    },
    get replaceSeparatorOutsideStrings () {
        return replaceSeparatorOutsideStrings;
    }
});
/**
 * Maps ColumnSummary type names to their Excel function equivalents.
 *
 * `custom` is intentionally omitted: a `customFunction` is arbitrary JavaScript
 * and has no generic Excel formula equivalent.  When `exportFormulas` is `true`,
 * cells with a `custom` summary type fall back to their pre-calculated static value.
 */ const SUMMARY_TYPE_TO_EXCEL_FN = {
    sum: 'SUM',
    min: 'MIN',
    max: 'MAX',
    count: 'COUNT',
    average: 'AVERAGE'
};
function colIndexToLetter(colIndex) {
    let letter = '';
    let n = colIndex;
    while(n > 0){
        const remainder = (n - 1) % 26;
        letter = String.fromCharCode(65 + remainder) + letter;
        n = Math.floor((n - 1) / 26);
    }
    return letter;
}
function colLetterToIndex(letters) {
    let index = 0;
    for(let i = 0; i < letters.length; i++){
        index = index * 26 + (letters.charCodeAt(i) - 64);
    }
    return index;
}
function isFormulaValue(value) {
    return typeof value === 'string' && value.startsWith('=');
}
function buildSummaryFormula(summary, dataRowOffset, dataColOffset) {
    const excelFn = SUMMARY_TYPE_TO_EXCEL_FN[summary.type];
    if (!excelFn) {
        return null;
    }
    const colLetter = colIndexToLetter(summary.sourceCol + dataColOffset);
    const rangeRefs = summary.sourceRanges.map(([start, end])=>{
        const startExcelRow = start + dataRowOffset;
        const endExcelRow = end + dataRowOffset;
        return startExcelRow === endExcelRow ? `${colLetter}${startExcelRow}` : `${colLetter}${startExcelRow}:${colLetter}${endExcelRow}`;
    });
    return {
        formula: `${excelFn}(${rangeRefs.join(',')})`
    };
}
function replaceSeparatorOutsideStrings(str, from, to) {
    let result = '';
    let inString = false;
    let stringChar = '';
    for(let i = 0; i < str.length; i++){
        const ch = str[i];
        if (inString) {
            result += ch;
            if (ch === stringChar) {
                if (str[i + 1] === stringChar) {
                    // Escaped quote (e.g. "" inside a double-quoted string) — consume
                    // both characters and remain in string mode.
                    result += str[i + 1];
                    i += 1;
                } else {
                    inString = false;
                }
            }
        } else if (ch === '"' || ch === '\'') {
            inString = true;
            stringChar = ch;
            result += ch;
        } else if (str.startsWith(from, i)) {
            result += to;
            i += from.length - 1;
        } else {
            result += ch;
        }
    }
    return result;
}
/**
 * Counts how many values in a `Set` are strictly less than `threshold`.
 *
 * @private
 * @param {Set<number>} set Set of numbers.
 * @param {number} threshold Upper bound (exclusive).
 * @returns {number}
 */ function countBelow(set, threshold) {
    let count = 0;
    set.forEach((value)=>{
        if (value < threshold) {
            count += 1;
        }
    });
    return count;
}
function normalizeFormula(formulaStr, separator, rowOffset, colOffset, excludedHiddenRows, excludedHiddenCols) {
    let formula = formulaStr.startsWith('=') ? formulaStr.slice(1) : formulaStr;
    const hasRowExclusions = excludedHiddenRows?.size > 0;
    const hasColExclusions = excludedHiddenCols?.size > 0;
    if (rowOffset !== 0 || colOffset !== 0 || hasRowExclusions || hasColExclusions) {
        // The leading alternative matches string literals (double-quoted Excel strings use "" to escape a quote;
        // single-quoted tokens are sheet name references like 'Sheet 1'!A1). When matched, they are returned
        // as-is so that cell-reference-like patterns inside string values are not offset.
        formula = formula.replace(/("(?:[^"]|"")*"|'[^']*')|(?<![0-9])(\$?)([A-Z]{1,3})(\$?)(\d{1,7})(?!\()/g, (match, strLiteral, colAbs, colLetters, rowAbs, rowStr)=>{
            if (strLiteral !== undefined) {
                return strLiteral;
            }
            const hotPhysCol = colLetterToIndex(colLetters) - 1; // 0-based physical HOT column
            const hotPhysRow = parseInt(rowStr, 10) - 1; // 0-based physical HOT row
            const hiddenColsBefore = hasColExclusions ? countBelow(excludedHiddenCols, hotPhysCol) : 0;
            const hiddenRowsBefore = hasRowExclusions ? countBelow(excludedHiddenRows, hotPhysRow) : 0;
            const newCol = colLetterToIndex(colLetters) + colOffset - hiddenColsBefore;
            const newRow = parseInt(rowStr, 10) + rowOffset - hiddenRowsBefore;
            return `${colAbs}${colIndexToLetter(newCol)}${rowAbs}${newRow}`;
        });
    }
    if (separator && separator !== ',') {
        formula = replaceSeparatorOutsideStrings(formula, separator, ',');
    }
    return formula;
}
