/**
 * 完整反混淆脚本 v2 - 先解码字符串，再 AST 清洗
 */
const fs = require('fs');
const path = require('path');
const vm = require('vm');

const deobfuscateIO = require('obfuscator-io-deobfuscator').deobfuscate;
const beautify = require('js-beautify').js;

const outputDir = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out';

function ensureDir(dir) {
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
}

/**
 * 提取并执行字符串解码器
 */
function setupDecoder(code) {
    // 查找字符串数组函数名 (如 _0x4ff4, _0x2b0b 等)
    const arrayFuncMatch = code.match(/function (_0x[a-f0-9]+)\(\)\{/);
    if (!arrayFuncMatch) return null;
    const arrayFuncName = arrayFuncMatch[1];

    // 查找解码函数名 (如 _0x56bd, _0xc90d 等)
    const decoderMatch = code.match(/function (_0x[a-f0-9]+)\(_0x[a-f0-9]+,_0x[a-f0-9]+\)\{const _0x[a-f0-9]+=_0x[a-f0-9]+\(\);/);
    if (!decoderMatch) return null;
    const decoderFuncName = decoderMatch[1];

    console.log(`  字符串数组函数: ${arrayFuncName}`);
    console.log(`  解码函数: ${decoderFuncName}`);

    // 提取字符串数组函数
    const arrayFuncStart = code.indexOf(`function ${arrayFuncName}(){`);
    let braceCount = 0, arrayFuncEnd = arrayFuncStart, foundStart = false;
    for (let i = arrayFuncStart; i < code.length; i++) {
        if (code[i] === '{') { braceCount++; foundStart = true; }
        else if (code[i] === '}') { braceCount--; if (foundStart && braceCount === 0) { arrayFuncEnd = i + 1; break; } }
    }
    const arrayFunc = code.substring(arrayFuncStart, arrayFuncEnd);

    // 提取解码函数
    const decoderStart = code.indexOf(`function ${decoderFuncName}(`);
    braceCount = 0; let decoderEnd = decoderStart; foundStart = false;
    for (let i = decoderStart; i < code.length; i++) {
        if (code[i] === '{') { braceCount++; foundStart = true; }
        else if (code[i] === '}') { braceCount--; if (foundStart && braceCount === 0) { decoderEnd = i + 1; break; } }
    }
    const decoderFunc = code.substring(decoderStart, decoderEnd);

    // 查找 IIFE
    const iifeStart = code.indexOf(';(function(_0x', arrayFuncEnd);
    if (iifeStart === -1) return null;

    // 查找 IIFE 结束
    const iifeEndPattern = `,${arrayFuncName})`;
    let iifeEnd = code.indexOf(iifeEndPattern, iifeStart);
    if (iifeEnd === -1) return null;
    iifeEnd = code.indexOf(';', iifeEnd) + 1;
    const iifeCode = code.substring(iifeStart, iifeEnd);

    // 在沙盒中执行
    const sandbox = { vip: 'cursor' };
    try {
        const setupCode = `${arrayFunc}\n${decoderFunc}\n${iifeCode}`;
        vm.runInNewContext(setupCode, sandbox);
        vm.runInNewContext(`globalThis.decoder = ${decoderFuncName};`, sandbox);
        return { sandbox, decoderFuncName, arrayFuncName, arrayFunc, decoderFunc, iifeCode };
    } catch (e) {
        console.log(`  沙盒执行失败: ${e.message}`);
        return null;
    }
}

/**
 * 解码所有字符串调用
 */
function decodeStrings(code, decoder) {
    if (!decoder) return code;

    const { sandbox, decoderFuncName } = decoder;

    // 查找所有别名
    const aliasPattern = new RegExp(`const (_0x[a-f0-9]+)=${decoderFuncName};`, 'g');
    const aliases = [decoderFuncName];
    let match;
    while ((match = aliasPattern.exec(code)) !== null) {
        aliases.push(match[1]);
    }
    console.log(`  解码函数别名: ${aliases.join(', ')}`);

    // 解码所有调用
    let decodedCount = 0;
    for (const alias of aliases) {
        const callPattern = new RegExp(`${alias}\\((0x[a-f0-9]+),'([^']+)'\\)`, 'g');
        code = code.replace(callPattern, (fullMatch, num, key) => {
            try {
                const decoded = vm.runInNewContext(`decoder(${num},'${key}')`, sandbox);
                if (typeof decoded === 'string') {
                    decodedCount++;
                    // 根据内容选择引号
                    if (decoded.includes('\n') || decoded.length > 200) {
                        return '`' + decoded.replace(/`/g, '\\`').replace(/\$/g, '\\$') + '`';
                    } else if (decoded.includes("'") && !decoded.includes('"')) {
                        return JSON.stringify(decoded);
                    } else {
                        return `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
                    }
                }
            } catch (e) {}
            return fullMatch;
        });
    }
    console.log(`  解码了 ${decodedCount} 个字符串`);

    // 移除解码器代码
    code = code.replace(decoder.arrayFunc, '/* [STRING ARRAY REMOVED] */');
    code = code.replace(decoder.decoderFunc, '/* [DECODER REMOVED] */');
    code = code.replace(decoder.iifeCode, '/* [IIFE REMOVED] */');

    // 移除别名
    for (const alias of aliases) {
        if (alias !== decoder.decoderFuncName) {
            code = code.replace(new RegExp(`const ${alias}=${decoder.decoderFuncName};`, 'g'), '');
        }
    }

    return code;
}

/**
 * AST 清洗
 */
function astClean(code, filename) {
    try {
        console.log(`  [AST] 处理 ${filename}...`);
        return deobfuscateIO(code);
    } catch (e) {
        console.log(`  [AST] 失败: ${e.message}`);
        return code;
    }
}

/**
 * 处理单个文件
 */
async function processFile(inputPath, outputPath, filename) {
    console.log(`\n========== ${filename} ==========`);

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

    // Step 1: 解码字符串
    console.log('\nStep 1: 解码字符串...');
    const decoder = setupDecoder(code);
    code = decodeStrings(code, decoder);

    // Step 2: AST 清洗
    console.log('\nStep 2: AST 清洗...');
    code = astClean(code, filename);

    // Step 3: 美化
    console.log('\nStep 3: 美化...');
    code = beautify(code, {
        indent_size: 4,
        preserve_newlines: true,
        max_preserve_newlines: 2
    });

    console.log(`处理后大小: ${(code.length / 1024).toFixed(2)} KB`);

    // 保存
    ensureDir(path.dirname(outputPath));
    fs.writeFileSync(outputPath, code);
    console.log(`✓ 已保存: ${outputPath}`);
}

// 主函数
async function main() {
    console.log('╔════════════════════════════════════════╗');
    console.log('║     完整反混淆脚本 v2                    ║');
    console.log('║     字符串解码 + AST清洗 + 美化          ║');
    console.log('╚════════════════════════════════════════╝\n');

    const files = [
        { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/webview/provider.js', output: 'webview/provider.js' },
        { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/extension.js', output: 'extension.js' },
        { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/account.js', output: 'utils/account.js' },
        { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/sqlite.js', output: 'utils/sqlite.js' },
    ];

    for (const file of files) {
        if (fs.existsSync(file.input)) {
            await processFile(file.input, path.join(outputDir, file.output), file.output);
        } else {
            console.log(`\n跳过: ${file.input} (不存在)`);
        }
    }

    console.log('\n╔════════════════════════════════════════╗');
    console.log('║     完成！                              ║');
    console.log('╚════════════════════════════════════════╝');
}

main().catch(console.error);
