const CONTEXT_VARIABLES = ['applicant', 'approver'];

const getSafeCode = (code) => {
    if (!code) return code;
    return code
        .replace(/（/g, '_')
        .replace(/）/g, '')
        .replace(/\(/g, '_')
        .replace(/\)/g, '')
        .replace(/、/g, '_')
        .replace(/，/g, '_')
        .replace(/%/g, '_')
        .replace(/=/g, '_')
        .replace(/：/g, '_')
        .replace(/\//g, '_')
        .replace(/-/g, '_')
        .replace(/\+/g, '_')
        .replace(/</g, '_')
        .replace(/>/g, '_')
        .replace(/\s+/g, '_')
        .replace(/\[/g, '_')
        .replace(/\]/g, '_')
        .replace(/\./g, '_')
        .replace(/_{2,}/g, '_')
        .replace(/_$/, '');
};

const isContextVariable = (code) => {
    return CONTEXT_VARIABLES.includes(code);
};

const mapFormula = (formula, tableFieldMap) => {
    if (!formula) return null;

    const trimmedFormula = formula.trim();
    if (trimmedFormula.startsWith('${')) return null;
    if (trimmedFormula === '{now}') return '${NOW()}';

    let newFormula = formula;

    // 预处理：修正生产数据中的非标准聚合函数语法
    // B: 全角括号 sum（{x}） → sum({x})
    newFormula = newFormula.replace(/(sum|average|count|max|min|numToRMB)\s*（/ig, '$1(');
    newFormula = newFormula.replace(/\}）/g, '})');
    // C: 缺失括号 sum{x} → sum({x})
    newFormula = newFormula.replace(/(sum|average|count|max|min|numToRMB)\{([^{}]*)\}/ig, '$1({$2})');
    // D: 清理 C 产生的冗余内层括号 sum({(金额)}) → sum({金额})
    newFormula = newFormula.replace(/(sum|average|count|max|min|numToRMB)\(\{\(([^)]+)\)\}\)/ig, '$1({$2})');

    const isFunction = newFormula.match(/(sum|average|count|max|min|numToRMB)\s*\(/i);
    const hasFieldRef = newFormula.match(/\{[^{}]+\}/);
    const isOperator = newFormula.match(/[\+\-\*\/]/) && hasFieldRef && newFormula.indexOf('}.') < 0;
    const isObjectField = newFormula.indexOf('}.') > -1;
    const isDotField = newFormula.match(/\{[^{}]+\.[^{}]+\}/);

    if (isFunction || isOperator || isObjectField || isDotField) {
        // 将数学分组方括号 [] 转为圆括号 ()，如 [{a}+{b}]/{c} → ({a}+{b})/{c}
        newFormula = newFormula.replace(/\[/g, '(').replace(/\]/g, ')');

        if (isFunction) {
            newFormula = newFormula.replace(/sum\s*\(/ig, 'SUM(');
            newFormula = newFormula.replace(/average\s*\(/ig, 'AVG(');
            newFormula = newFormula.replace(/count\s*\(/ig, 'COUNT(');
            newFormula = newFormula.replace(/max\s*\(/ig, 'MAX(');
            newFormula = newFormula.replace(/min\s*\(/ig, 'MIN(');
            newFormula = newFormula.replace(/numToRMB\s*\(/ig, 'UPPERMONEY(');
        }

        newFormula = newFormula.replace(/\{([^{}]+)\}\./g, (match, code) => {
            const trimmedCode = code.trim();
            if (isContextVariable(trimmedCode)) {
                return `${trimmedCode}.`;
            }
            return `${getSafeCode(trimmedCode)}__expand.`;
        });

        newFormula = newFormula.replace(/\{([^{}]+)\}/g, (match, code) => {
            code = code.trim();
            if (code === 'now') {
                return 'NOW()';
            }
            if (tableFieldMap && tableFieldMap[code]) {
                const tableCode = tableFieldMap[code];
                const safeTableCode = getSafeCode(tableCode);
                return `ARRAYMAP(${safeTableCode}, item => item['${code}'])`;
            }
            if (code.indexOf('.') > -1) {
                const parts = code.split('.');
                const firstPart = parts[0].trim();
                if (isContextVariable(firstPart)) {
                    return `${firstPart}.${parts.slice(1).join('.')}`;
                }
                return `${getSafeCode(firstPart)}__expand.${parts.slice(1).join('.')}`;
            }
            return getSafeCode(code);
        });

        return `\${${newFormula}}`;
    }

    if (trimmedFormula.startsWith('{') && trimmedFormula.endsWith('}')) {
        const innerCode = trimmedFormula.slice(1, -1).trim();
        if (innerCode === 'now') {
            return '${NOW()}';
        }
        return `\${${getSafeCode(innerCode)}}`;
    }

    return null;
};

const getTableFieldMap = (fields) => {
    const map = {};
    if (!fields) return map;
    fields.forEach((field) => {
        if (field.type === 'table' && field.fields) {
            field.fields.forEach((col) => {
                map[col.code] = field.code;
            });
        }
        if (field.type === 'section' && field.fields) {
            Object.assign(map, getTableFieldMap(field.fields));
        }
    });
    return map;
};

module.exports = {
    getSafeCode,
    mapFormula,
    getTableFieldMap
};
