/**
 * 通用解码脚本 - 使用 eval 执行解码器
 * 为每个混淆文件生成解码映射
 */
const fs = require('fs');
const path = require('path');

const baseDir = 'D:/temp/破解/cursorpro-0.4.5';

// 全局变量
var vip = 'cursor';

/**
 * 为单个文件生成解码映射
 */
function generateMapForFile(inputPath, outputPath, filename) {
    console.log(`\n${'='.repeat(50)}`);
    console.log(`处理: ${filename}`);
    console.log('='.repeat(50));

    // 检查是否已存在
    if (fs.existsSync(outputPath)) {
        const existing = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
        console.log(`已存在: ${Object.keys(existing).length} 条映射`);
        return;
    }

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

    // 1. 找函数名
    const funcMatch = code.match(/function (_0x[a-f0-9]+)\(/g);
    if (!funcMatch) {
        console.log('未找到函数');
        return;
    }
    const funcNames = [...new Set(funcMatch)].map(f => f.match(/_0x[a-f0-9]+/)[0]);
    console.log(`找到 ${funcNames.length} 个函数`);

    // 2. 找字符串数组函数 (无参数的函数)
    const arrFuncName = funcNames.find(n => {
        const regex = new RegExp(`function ${n}\\(\\)\\s*\\{`);
        return regex.test(code);
    });
    if (!arrFuncName) {
        console.log('未找到字符串数组函数');
        return;
    }
    console.log(`字符串数组函数: ${arrFuncName}`);

    // 3. 提取并执行字符串数组函数
    const arrMatch = code.match(new RegExp(`function ${arrFuncName}\\(\\)[\\s\\S]*?return ${arrFuncName}\\(\\);\\}`));
    if (!arrMatch) {
        console.log('无法提取字符串数组函数');
        return;
    }

    try {
        eval(arrMatch[0]);
        console.log('字符串数组函数已定义');
    } catch (e) {
        console.log(`字符串数组函数执行失败: ${e.message}`);
        return;
    }

    // 4. 找解码函数 (两个参数的函数)
    const decFuncName = funcNames.find(n => {
        const regex = new RegExp(`function ${n}\\s*\\(\\s*_0x[a-f0-9]+\\s*,\\s*_0x[a-f0-9]+\\s*\\)\\s*\\{`);
        return regex.test(code) && n !== arrFuncName;
    });
    if (!decFuncName) {
        console.log('未找到解码函数');
        return;
    }
    console.log(`解码函数: ${decFuncName}`);

    // 5. 提取并执行解码函数
    const decStart = code.indexOf(`function ${decFuncName}(`);
    let braceCount = 0, decEnd = decStart, foundStart = false;
    for (let i = decStart; i < code.length; i++) {
        if (code[i] === '{') { braceCount++; foundStart = true; }
        else if (code[i] === '}') {
            braceCount--;
            if (foundStart && braceCount === 0) {
                decEnd = i + 1;
                break;
            }
        }
    }
    const decCode = code.substring(decStart, decEnd);

    try {
        eval(decCode);
        console.log('解码函数已定义');
    } catch (e) {
        console.log(`解码函数执行失败: ${e.message}`);
        return;
    }

    // 6. 执行 IIFE (初始化洗牌)
    // 查找 IIFE: (function(...){...})(...,_0xXXXX,...)
    const iifePattern = new RegExp(`\\(function\\s*\\([^)]*\\)\\s*\\{[\\s\\S]*?\\}\\)\\s*\\([^,]+,[^,]+,\\s*${arrFuncName}\\s*,[^)]+\\)`, 'g');
    const iifeMatches = code.match(iifePattern);

    if (iifeMatches) {
        for (const iifeCode of iifeMatches) {
            try {
                eval(iifeCode);
                console.log('IIFE 已执行');
                break;
            } catch (e) {
                console.log(`IIFE 执行失败: ${e.message}`);
            }
        }
    } else {
        // 尝试另一种 IIFE 模式
        const altIife = code.match(/;\s*\(function\s*\([^)]*\)\s*\{[\s\S]*?\}\)\s*\([^)]+\)\s*;/);
        if (altIife) {
            try {
                eval(altIife[0]);
                console.log('备用 IIFE 已执行');
            } catch (e) {
                console.log(`备用 IIFE 执行失败: ${e.message}`);
            }
        }
    }

    // 7. 获取解码函数引用
    let decode;
    try {
        decode = eval(decFuncName);
        if (typeof decode !== 'function') {
            console.log('解码函数不是函数');
            return;
        }
        console.log('解码函数可用');
    } catch (e) {
        console.log(`获取解码函数失败: ${e.message}`);
        return;
    }

    // 8. 收集所有调用并解码
    const regex = /_0x[a-zA-Z0-9]+\s*\(\s*(0x[0-9a-fA-F]+)\s*,\s*'([^']+)'\s*\)/g;
    const decodedMap = {};
    let match;
    let successCount = 0;
    let failCount = 0;

    while ((match = regex.exec(code)) !== null) {
        const fullMatch = match[0];
        const index = parseInt(match[1], 16);
        const key = match[2];

        if (!decodedMap[fullMatch]) {
            try {
                const decoded = decode(index, key);
                if (typeof decoded === 'string') {
                    decodedMap[fullMatch] = decoded;
                    successCount++;
                } else {
                    failCount++;
                }
            } catch (e) {
                failCount++;
            }
        }
    }

    console.log(`成功解码: ${successCount}`);
    console.log(`解码失败: ${failCount}`);

    // 9. 保存映射
    if (successCount > 0) {
        fs.writeFileSync(outputPath, JSON.stringify(decodedMap, null, 2));
        console.log(`已保存: ${outputPath}`);
    }
}

// 主函数
function main() {
    console.log('╔════════════════════════════════════════════════════╗');
    console.log('║             通用解码映射生成器                       ║');
    console.log('║              使用 eval 执行解码器                    ║');
    console.log('╚════════════════════════════════════════════════════╝');

    const files = [
        { input: '原版本/extension/out/webview/provider.js', output: 'provider_decoded_map.json' },
        { input: '原版本/extension/out/extension.js', output: 'extension_decoded_map.json' },
        { input: '原版本/extension/out/utils/account.js', output: 'account_decoded_map.json' },
        { input: '原版本/extension/out/utils/sqlite.js', output: 'sqlite_decoded_map.json' },
        { input: '原版本/extension/out/api/client.js', output: 'client_decoded_map.json' }
    ];

    for (const file of files) {
        const inputPath = path.join(baseDir, file.input);
        const outputPath = path.join(baseDir, file.output);

        if (!fs.existsSync(inputPath)) {
            console.log(`\n跳过: ${file.input} (不存在)`);
            continue;
        }

        generateMapForFile(inputPath, outputPath, file.input);
    }

    console.log('\n' + '='.repeat(50));
    console.log('完成！');
}

main();
