/**
 * 第四轮 - 基于使用点的精确重命名
 */
const fs = require('fs');
const babel = require('@babel/core');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');

const inputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';
const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';

console.log('╔════════════════════════════════════════════════════╗');
console.log('║       第四轮精确变量重命名                          ║');
console.log('╚════════════════════════════════════════════════════╝');

const code = fs.readFileSync(inputPath, 'utf8');
console.log(`读取文件: ${(code.length / 1024).toFixed(2)} KB`);

console.log('\n[1] 解析 AST...');
let ast;
try {
    ast = babel.parseSync(code, { sourceType: 'script' });
    console.log('AST 解析成功');
} catch (e) {
    console.error('AST 解析失败:', e.message);
    process.exit(1);
}

const usedNames = new Map();

function getUniqueName(scope, baseName) {
    const key = scope.uid;
    if (!usedNames.has(key)) usedNames.set(key, new Set());
    const used = usedNames.get(key);

    // 也检查 scope bindings
    let name = baseName;
    let counter = 1;
    while (used.has(name) || scope.hasBinding(name)) {
        name = baseName + counter++;
    }
    used.add(name);
    return name;
}

console.log('\n[2] 分析对象属性赋值...');
let renamedCount = 0;

// 收集变量被赋值到哪些属性
const varToProps = new Map();

traverse(ast, {
    ObjectProperty(path) {
        const key = path.node.key;
        const value = path.node.value;

        // { 'prop': varXXX }
        if (t.isIdentifier(value) && /^(var|v)\d+$/.test(value.name)) {
            let propName;
            if (t.isStringLiteral(key)) propName = key.value;
            else if (t.isIdentifier(key)) propName = key.name;

            if (propName) {
                if (!varToProps.has(value.name)) {
                    varToProps.set(value.name, new Set());
                }
                varToProps.get(value.name).add(propName);
            }
        }
    }
});

// 属性名到变量名的映射
const propToVarName = {
    'is_injected': 'isInjected',
    'workbench_path': 'workbenchPath',
    'cursor_path': 'cursorPath',
    'machine_id': 'machineId',
    'email': 'email',
    'token': 'token',
    'success': 'success',
    'error': 'errorMsg',
    'message': 'message',
    'data': 'data',
    'result': 'result',
    'status': 'status',
    'enabled': 'enabled',
    'online': 'isOnline',
    'running': 'isRunning',
    'installed': 'isInstalled',
    'injected': 'isInjected',
    'can_switch': 'canSwitch',
    'switch_remaining': 'switchRemaining',
    'expire_date': 'expireDate',
    'version': 'version',
    'path': 'filePath',
    'content': 'content',
    'type': 'msgType',
};

// 推断变量名
const inferredNames = new Map();
for (const [varName, props] of varToProps) {
    for (const prop of props) {
        if (propToVarName[prop]) {
            inferredNames.set(varName, propToVarName[prop]);
            break;
        }
    }
}

console.log(`从属性推断了 ${inferredNames.size} 个变量名`);

// 应用推断
traverse(ast, {
    VariableDeclarator(path) {
        if (!t.isIdentifier(path.node.id)) return;
        const varName = path.node.id.name;

        if (!inferredNames.has(varName)) return;

        const binding = path.scope.getBinding(varName);
        if (!binding) return;

        const newName = getUniqueName(path.scope, inferredNames.get(varName));
        path.node.id.name = newName;
        binding.referencePaths.forEach(ref => {
            ref.node.name = newName;
        });
        renamedCount++;
    }
});

console.log(`重命名了 ${renamedCount} 个变量`);

// 第二轮：基于初始化值
console.log('\n[3] 分析初始化值...');
let initCount = 0;

traverse(ast, {
    VariableDeclarator(path) {
        if (!t.isIdentifier(path.node.id)) return;
        const varName = path.node.id.name;
        if (!/^(var|v|arg)\d+$/.test(varName)) return;

        const init = path.node.init;
        let newName = null;

        // 布尔字面量
        if (t.isBooleanLiteral(init)) {
            // 检查使用上下文
            const binding = path.scope.getBinding(varName);
            if (binding) {
                for (const ref of binding.referencePaths) {
                    if (t.isObjectProperty(ref.parent)) {
                        const key = ref.parent.key;
                        let prop;
                        if (t.isStringLiteral(key)) prop = key.value;
                        else if (t.isIdentifier(key)) prop = key.name;
                        if (prop && propToVarName[prop]) {
                            newName = propToVarName[prop];
                            break;
                        }
                    }
                }
            }
            if (!newName) newName = init.value ? 'isTrue' : 'isFalse';
        }

        // 数组字面量
        if (t.isArrayExpression(init) && init.elements.length === 0) {
            newName = 'items';
        }

        // 字符串字面量
        if (t.isStringLiteral(init)) {
            const val = init.value;
            if (val.includes('/') || val.includes('\\')) newName = 'pathStr';
            else if (val.includes('@')) newName = 'emailStr';
            else if (val.length > 50) newName = 'longStr';
            else newName = 'str';
        }

        // 数字字面量
        if (t.isNumericLiteral(init)) {
            if (init.value === 0) newName = 'count';
            else newName = 'num';
        }

        // 正则表达式
        if (t.isRegExpLiteral(init)) {
            newName = 'regex';
        }

        if (newName) {
            const binding = path.scope.getBinding(varName);
            if (binding) {
                const finalName = getUniqueName(path.scope, newName);
                path.node.id.name = finalName;
                binding.referencePaths.forEach(ref => {
                    ref.node.name = finalName;
                });
                initCount++;
            }
        }
    }
});

console.log(`基于初始化值重命名了 ${initCount} 个变量`);

console.log('\n[4] 生成代码...');
const output = generate(ast, {
    comments: false,
    compact: false,
    concise: false
}, code);

let finalCode = output.code;
finalCode = finalCode.replace(/\["([a-zA-Z_$][a-zA-Z0-9_$]*)"\]/g, '.$1');

console.log('\n[5] 保存文件...');
fs.writeFileSync(outputPath, finalCode);
console.log(`保存到: ${outputPath}`);
console.log(`新文件大小: ${(finalCode.length / 1024).toFixed(2)} KB`);

const remaining = (finalCode.match(/\b(var|arg|v)\d+\b/g) || []);
const unique = [...new Set(remaining)];
console.log(`\n剩余通用变量名: ${unique.length} 个唯一名称`);

console.log('\n✅ 完成！');
