/**
 * 完整反混淆 provider.js
 * 使用 RC4 + 非标准 Base64 解码
 */
const fs = require('fs');
const path = require('path');

// 非标准 Base64 字母表（小写在前）
const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';

/**
 * 非标准 Base64 解码
 */
function base64Decode(input) {
    let output = '';
    let buffer = 0;
    let bitsCollected = 0;

    for (let i = 0; i < input.length; i++) {
        const char = input[i];
        if (char === '=') break;

        const value = BASE64_CHARS.indexOf(char);
        if (value === -1) continue;

        buffer = (buffer << 6) | value;
        bitsCollected += 6;

        if (bitsCollected >= 8) {
            bitsCollected -= 8;
            output += String.fromCharCode((buffer >> bitsCollected) & 0xFF);
        }
    }

    return output;
}

/**
 * RC4 解密
 */
function rc4Decrypt(data, key) {
    const s = [];
    let j = 0;
    let result = '';

    // 初始化 S-box
    for (let i = 0; i < 256; i++) {
        s[i] = i;
    }

    // 密钥调度
    for (let i = 0; i < 256; i++) {
        j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
        [s[i], s[j]] = [s[j], s[i]];
    }

    // 生成密钥流并解密
    let i = 0;
    j = 0;
    for (let k = 0; k < data.length; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        [s[i], s[j]] = [s[j], s[i]];
        const keyByte = s[(s[i] + s[j]) % 256];
        result += String.fromCharCode(data.charCodeAt(k) ^ keyByte);
    }

    return result;
}

/**
 * 解码单个字符串
 */
function decodeString(encoded, key) {
    try {
        const base64Decoded = base64Decode(encoded);
        const decrypted = rc4Decrypt(base64Decoded, key);
        return decrypted;
    } catch (e) {
        return null;
    }
}

/**
 * 从代码中提取字符串数组
 */
function extractStringArray(code) {
    // 找到字符串数组函数
    const arrayMatch = code.match(/function\s+_0x[a-f0-9]+\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{\s*return\s*\[vip,([\s\S]*?)\]\.concat/);

    if (!arrayMatch) {
        console.log('未找到字符串数组，尝试其他模式...');
        // 尝试直接匹配数组内容
        const directMatch = code.match(/return\s*\[\s*vip\s*,\s*'([^']+)'/);
        if (directMatch) {
            console.log('找到数组起始');
        }
        return null;
    }

    console.log('找到字符串数组定义');

    // 提取所有字符串
    const arrayContent = arrayMatch[1];
    const strings = ['cursor']; // vip = 'cursor'

    // 匹配所有字符串
    const stringRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
    let match;
    while ((match = stringRegex.exec(arrayContent)) !== null) {
        strings.push(match[1]);
    }

    console.log(`提取了 ${strings.length} 个字符串`);
    return strings;
}

/**
 * 动态执行提取字符串数组
 */
function extractStringArrayDynamic(code) {
    console.log('使用动态方法提取字符串数组...');

    // 提取 _0x4ff4 或类似函数
    const funcMatch = code.match(/(function\s+(_0x[a-f0-9]+)\(\)\s*\{[\s\S]*?return\s+_0x[a-f0-9]+;\s*\})/);

    if (!funcMatch) {
        console.log('未找到字符串数组函数');
        return null;
    }

    const funcName = funcMatch[2];
    console.log(`找到函数: ${funcName}`);

    // 提取完整的数组定义部分
    // 找到 concat 链的结束
    let depth = 0;
    let start = code.indexOf('return[vip,');
    if (start === -1) start = code.indexOf("return [vip,");
    if (start === -1) {
        console.log('未找到数组起始');
        return null;
    }

    let end = start;
    let inString = false;
    let stringChar = '';

    for (let i = start; i < code.length; i++) {
        const char = code[i];

        if (!inString) {
            if (char === '"' || char === "'") {
                inString = true;
                stringChar = char;
            } else if (char === '[') {
                depth++;
            } else if (char === ']') {
                depth--;
                if (depth === 0) {
                    // 检查后面是否还有 .concat
                    const after = code.slice(i + 1, i + 20);
                    if (!after.match(/^\s*\.\s*concat/)) {
                        end = i + 1;
                        break;
                    }
                }
            }
        } else {
            if (char === stringChar && code[i-1] !== '\\') {
                inString = false;
            }
        }
    }

    // 构建可执行代码
    const arrayCode = `
        var vip = 'cursor';
        ${code.slice(start, end)};
    `;

    try {
        const result = eval(arrayCode);
        console.log(`动态提取了 ${result.length} 个字符串`);
        return result;
    } catch (e) {
        console.log('动态执行失败:', e.message);
        return null;
    }
}

/**
 * 手动解析提取字符串数组
 */
function extractStringsManual(code) {
    console.log('使用手动解析方法...');

    const strings = ['cursor'];

    // 找到所有在数组中的字符串字面量
    // 模式: 'xxxxx' 在数组上下文中
    const regex = /\[vip,([\s\S]*?)\]\.concat\(\(function\(\)/g;
    let match;

    while ((match = regex.exec(code)) !== null) {
        const content = match[1];
        const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
        let strMatch;
        while ((strMatch = strRegex.exec(content)) !== null) {
            strings.push(strMatch[1].replace(/\\'/g, "'"));
        }
    }

    // 继续查找 concat 中的字符串
    const concatRegex = /return\s*\[([\s\S]*?)\](?:\s*;\s*\}|\s*\.\s*concat)/g;
    while ((match = concatRegex.exec(code)) !== null) {
        const content = match[1];
        if (content.includes('vip')) continue; // 跳过第一个

        const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
        let strMatch;
        while ((strMatch = strRegex.exec(content)) !== null) {
            const str = strMatch[1].replace(/\\'/g, "'");
            if (!strings.includes(str)) {
                strings.push(str);
            }
        }
    }

    console.log(`手动提取了 ${strings.length} 个字符串`);
    return strings;
}

/**
 * 在沙盒中执行代码提取字符串数组
 */
function extractWithSandbox(code) {
    console.log('尝试沙盒执行...');

    // 找到字符串数组函数名
    const funcNameMatch = code.match(/function\s+(_0x[a-f0-9]+)\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{/);
    if (!funcNameMatch) {
        console.log('未找到数组函数');
        return null;
    }

    const funcName = funcNameMatch[1];
    console.log(`数组函数名: ${funcName}`);

    // 提取整个函数定义
    const funcStart = code.indexOf(`function ${funcName}()`);
    let braceCount = 0;
    let funcEnd = funcStart;
    let started = false;

    for (let i = funcStart; i < code.length; i++) {
        if (code[i] === '{') {
            braceCount++;
            started = true;
        } else if (code[i] === '}') {
            braceCount--;
            if (started && braceCount === 0) {
                funcEnd = i + 1;
                break;
            }
        }
    }

    const funcCode = code.slice(funcStart, funcEnd);

    // 执行并获取结果
    const execCode = `
        var vip = 'cursor';
        ${funcCode}
        ${funcName}();
    `;

    try {
        const result = eval(execCode);
        console.log(`沙盒执行成功，获取 ${result.length} 个字符串`);
        return result;
    } catch (e) {
        console.log('沙盒执行失败:', e.message);
        return null;
    }
}

/**
 * 主函数
 */
async function main() {
    console.log('╔════════════════════════════════════════════════════╗');
    console.log('║         Provider.js 完整反混淆工具                  ║');
    console.log('╚════════════════════════════════════════════════════╝');

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

    // 读取文件
    console.log('\n[1] 读取文件...');
    let code = fs.readFileSync(inputPath, 'utf8');
    console.log(`文件大小: ${(code.length / 1024).toFixed(2)} KB`);

    // 提取字符串数组
    console.log('\n[2] 提取字符串数组...');
    let stringArray = extractWithSandbox(code);

    if (!stringArray || stringArray.length < 100) {
        console.log('沙盒方法失败，尝试手动解析...');
        stringArray = extractStringsManual(code);
    }

    if (!stringArray || stringArray.length < 10) {
        console.log('错误：无法提取字符串数组');
        return;
    }

    console.log(`成功提取 ${stringArray.length} 个编码字符串`);

    // 找到解码器函数名和密钥
    console.log('\n[3] 分析解码器...');
    const decoderMatch = code.match(/const\s+(_0x[a-f0-9]+)\s*=\s*(_0x[a-f0-9]+);/);
    let decoderName = '_0x56bd';
    let decoderAlias = '_0xa6d6ac';

    if (decoderMatch) {
        decoderAlias = decoderMatch[1];
        decoderName = decoderMatch[2];
        console.log(`解码器: ${decoderName}, 别名: ${decoderAlias}`);
    }

    // 构建解码映射
    console.log('\n[4] 解码字符串...');
    const decodeMap = new Map();
    let decodedCount = 0;

    // 找到所有解码器调用: _0x56bd(0x123, 'key') 或 _0xa6d6ac(0x123, 'key')
    const callPattern = new RegExp(
        `(?:${decoderName}|${decoderAlias})\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`,
        'gi'
    );

    const calls = new Set();
    let callMatch;
    while ((callMatch = callPattern.exec(code)) !== null) {
        calls.add(JSON.stringify([callMatch[0], callMatch[1], callMatch[2]]));
    }

    console.log(`找到 ${calls.size} 个唯一的解码器调用`);

    // 解码每个调用
    const baseIndex = 0x107; // 从混淆代码中提取的基准索引

    for (const callStr of calls) {
        const [fullMatch, indexHex, key] = JSON.parse(callStr);
        const index = parseInt(indexHex, 16) - baseIndex;

        if (index >= 0 && index < stringArray.length) {
            const encoded = stringArray[index];
            const decoded = decodeString(encoded, key);

            if (decoded && decoded.length > 0 && !decoded.includes('\x00')) {
                decodeMap.set(fullMatch, decoded);
                decodedCount++;
            }
        }
    }

    console.log(`成功解码 ${decodedCount} 个字符串`);

    // 替换代码中的调用
    console.log('\n[5] 替换代码...');
    let newCode = code;
    let replaceCount = 0;

    for (const [pattern, decoded] of decodeMap) {
        // 转义特殊字符用于字符串
        let replacement;
        if (decoded.includes('\n') || decoded.includes('\r') || decoded.includes('`')) {
            // 使用 JSON.stringify 处理复杂字符串
            replacement = JSON.stringify(decoded);
        } else if (decoded.includes("'") && !decoded.includes('"')) {
            replacement = `"${decoded}"`;
        } else {
            replacement = `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
        }

        const before = newCode.length;
        newCode = newCode.split(pattern).join(replacement);
        if (newCode.length !== before) {
            replaceCount++;
        }
    }

    console.log(`替换了 ${replaceCount} 个模式`);

    // 清理代码
    console.log('\n[6] 清理代码...');

    // 简化属性访问
    newCode = newCode.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1');

    // 替换布尔值
    newCode = newCode.replace(/!!\[\]/g, 'true');
    newCode = newCode.replace(/!\[\]/g, 'false');

    // 保存
    console.log('\n[7] 保存文件...');
    const outputDir = path.dirname(outputPath);
    if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
    }

    fs.writeFileSync(outputPath, newCode);
    console.log(`保存到: ${outputPath}`);
    console.log(`新文件大小: ${(newCode.length / 1024).toFixed(2)} KB`);

    // 保存解码映射供调试
    const mapPath = 'D:/temp/破解/cursorpro-0.4.5/provider_decode_map.json';
    const mapObj = {};
    for (const [k, v] of decodeMap) {
        if (v.length < 500) { // 只保存较短的字符串
            mapObj[k] = v;
        }
    }
    fs.writeFileSync(mapPath, JSON.stringify(mapObj, null, 2));
    console.log(`解码映射保存到: ${mapPath}`);

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

main().catch(console.error);
