/**
 * 第二轮变量重命名 - 处理 API 调用结果和常见模式
 */
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',
        plugins: []
    });
    console.log('AST 解析成功');
} catch (e) {
    console.error('AST 解析失败:', e.message);
    process.exit(1);
}

console.log('\n[2] 智能变量重命名...');
let renamedCount = 0;

const usedNamesPerScope = new Map();

function getScopeUsedNames(scope) {
    if (!usedNamesPerScope.has(scope.uid)) {
        usedNamesPerScope.set(scope.uid, new Set());
    }
    return usedNamesPerScope.get(scope.uid);
}

function isNameUsedInScope(scope, name) {
    if (scope.hasBinding(name)) return true;
    let s = scope;
    while (s) {
        if (getScopeUsedNames(s).has(name)) return true;
        s = s.parent;
    }
    return false;
}

function renameBinding(path, varName, newName) {
    const scope = path.scope;
    let finalName = newName;
    let counter = 1;
    while (isNameUsedInScope(scope, finalName)) {
        finalName = newName + counter++;
    }

    getScopeUsedNames(scope).add(finalName);

    const binding = scope.getBinding(varName);
    if (binding) {
        path.node.id.name = finalName;
        binding.referencePaths.forEach(ref => {
            ref.node.name = finalName;
        });
        return true;
    }
    return false;
}

// API 调用模式匹配
const apiPatterns = {
    'verifyKey': 'verifyResult',
    'switchSeamlessToken': 'switchResult',
    'getAccount': 'accountResult',
    'getUsage': 'usageResult',
    'getAnnouncement': 'announcement',
    'checkVersion': 'versionResult',
    'getProxyStatus': 'proxyStatus',
    'getSeamlessStatus': 'seamlessStatus',
};

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

        if (!/^var\d+$/.test(varName)) return;

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

        // await client_1.xxx() -> xxxResult
        if (t.isAwaitExpression(init)) {
            const arg = init.argument;
            if (t.isCallExpression(arg)) {
                const callee = arg.callee;
                if (t.isMemberExpression(callee)) {
                    const objName = callee.object.name || '';
                    const methodName = callee.property.name || '';

                    // client_1.xxx
                    if (objName === 'client_1' && apiPatterns[methodName]) {
                        newName = apiPatterns[methodName];
                    }
                    // this._xxx
                    else if (t.isThisExpression(callee.object)) {
                        if (methodName.startsWith('_get')) {
                            const base = methodName.slice(4);
                            newName = base.charAt(0).toLowerCase() + base.slice(1);
                        } else if (methodName.startsWith('_check')) {
                            newName = 'checkResult';
                        }
                    }
                    // xxx.exec()
                    else if (methodName === 'exec') {
                        newName = 'execResult';
                    }
                }
            }
        }

        // 字符串方法调用结果
        if (t.isCallExpression(init)) {
            const callee = init.callee;
            if (t.isMemberExpression(callee)) {
                const methodName = callee.property.name || '';

                if (methodName === 'replace') newName = 'replaced';
                else if (methodName === 'trim') newName = 'trimmed';
                else if (methodName === 'toLowerCase') newName = 'lowerStr';
                else if (methodName === 'toUpperCase') newName = 'upperStr';
                else if (methodName === 'slice') newName = 'sliced';
                else if (methodName === 'substring') newName = 'substr';
                else if (methodName === 'concat') newName = 'concatenated';
                else if (methodName === 'normalize') newName = 'normalized';
            }
        }

        if (newName && renameBinding(path, varName, newName)) {
            renamedCount++;
        }
    }
});

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

console.log('\n[3] 处理方法参数...');
let paramCount = 0;

// 收集方法名和参数的映射
const methodParamNames = {
    'constructor': ['extensionUri', 'context'],
    '_handleActivate': ['key'],
    '_handleSwitch': [],
    '_handleReset': [],
    '_handleDisable': [],
    '_writeAccountToLocal': ['accountData'],
    '_writeHostsFile': ['content'],
    '_handleToggleProxy': ['enabled', 'silent'],
    '_handleToggleSeamless': ['enabled'],
    '_handleGetAccountUsage': ['forceRefresh'],
    '_handleCheckUsageBeforeSwitch': ['silent'],
    '_postMessage': ['message'],
    '_grantHostsWritePermission': [],
    'resolveWebviewView': ['webviewView', 'context', 'token'],
    '_handleInjectSeamless': [],
    '_handleRestoreSeamless': [],
    '_handleManualSeamlessSwitch': [],
};

traverse(ast, {
    ClassMethod(path) {
        const methodName = path.node.key.name || '';
        const expectedParams = methodParamNames[methodName];

        if (!expectedParams) return;

        const params = path.node.params;
        for (let i = 0; i < params.length && i < expectedParams.length; i++) {
            const param = params[i];
            const newName = expectedParams[i];
            if (!newName) continue; // 跳过空名称
            if (t.isIdentifier(param) && /^arg\d+$/.test(param.name)) {
                const binding = path.scope.getBinding(param.name);
                if (binding) {
                    param.name = newName;
                    binding.referencePaths.forEach(ref => {
                        ref.node.name = newName;
                    });
                    paramCount++;
                }
            }
        }
    }
});

console.log(`重命名了 ${paramCount} 个参数`);

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)\d+\b/g) || []);
const unique = [...new Set(remaining)];
console.log(`\n剩余通用变量名: ${unique.length} 个唯一名称`);

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