/**
 * 反混淆并美化原版 extension/out 下的核心文件，输出到 codexfanbianyi/extension/out。
 * 策略：动态执行字符串数组 + 解码函数，解出所有形如 _0x****(0x123,'key') 的调用并替换为明文，再用 js-beautify 排版。
 */
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const beautify = require('js-beautify').js;

const baseDir = __dirname;
const inputBase = path.join(baseDir, '原版本', 'extension', 'out');
const outputBase = path.join(baseDir, 'codexfanbianyi', 'extension', 'out');

const targets = [
    'webview/provider.js',
    'extension.js',
    'utils/account.js',
    'utils/sqlite.js',
    'api/client.js'
];

const mapPaths = {
    'webview/provider.js': path.join(baseDir, 'provider_decoded_map.json'),
    'extension.js': path.join(baseDir, 'extension_decoded_map.json'),
    'utils/account.js': path.join(baseDir, 'account_decoded_map.json'),
    'utils/sqlite.js': path.join(baseDir, 'sqlite_decoded_map.json'),
    'api/client.js': path.join(baseDir, 'client_decoded_map.json')
};

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

function extractFunctionWithBody(code, nameRegex) {
    const match = nameRegex.exec(code);
    if (!match) return null;

    const start = match.index;
    const braceStart = code.indexOf('{', start);
    if (braceStart === -1) return null;

    let depth = 0;
    for (let i = braceStart; i < code.length; i++) {
        const ch = code[i];
        if (ch === '{') depth++;
        else if (ch === '}') {
            depth--;
            if (depth === 0) {
                return {
                    name: match[1],
                    code: code.slice(start, i + 1),
                    end: i + 1
                };
            }
        }
    }
    return null;
}

function buildSandbox() {
    const sandbox = {
        console: { log: () => {}, warn: () => {}, error: () => {} },
        vip: 'cursor',
        Buffer,
        atob: (str) => Buffer.from(str, 'base64').toString('binary'),
        btoa: (str) => Buffer.from(str, 'binary').toString('base64'),
        decodeURIComponent,
        encodeURIComponent,
        parseInt,
        String,
        setTimeout,
        clearTimeout,
        setInterval,
        clearInterval,
        exports: {},
        module: { exports: {} },
        require: () => ({})
    };
    vm.createContext(sandbox);
    return sandbox;
}

function buildDecoder(code) {
    const arrayFunc = extractFunctionWithBody(code, /function\s+(_0x[a-f0-9]+)\s*\(\s*\)/i);
    const decoderFunc = extractFunctionWithBody(code, /function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)/i);

    if (!arrayFunc || !decoderFunc) {
        return null;
    }

    const sandbox = buildSandbox();
    try {
        // 1) 先只注入字符串数组函数 + 解码函数（避免执行到 exports/require 等顶层逻辑）
        vm.runInContext(`${arrayFunc.code}\n${decoderFunc.code}`, sandbox, { timeout: 4000 });

        // 2) 执行“数组旋转/IIFE”等启动代码（通常位于文件开头，exports 之前）
        const stopMarkers = [
            'var __createBinding',
            'Object.defineProperty(exports',
            'exports.',
            'module.exports'
        ];
        let bootstrapEnd = code.length;
        for (const marker of stopMarkers) {
            const idx = code.indexOf(marker);
            if (idx !== -1 && idx < bootstrapEnd) bootstrapEnd = idx;
        }
        const bootstrapCode = code.slice(0, bootstrapEnd);
        vm.runInContext(bootstrapCode, sandbox, { timeout: 4000 });

        const decoder = sandbox[decoderFunc.name];
        if (typeof decoder !== 'function') {
            console.warn(`  解码器 ${decoderFunc.name} 不是函数`);
            return null;
        }
        return decoder.bind(sandbox);
    } catch (e) {
        console.warn(`  解码器初始化失败: ${e.message}`);
        return null;
    }
}

function literalFor(decoded) {
    if (decoded == null) return 'undefined';
    if (typeof decoded !== 'string') return JSON.stringify(decoded);
    if (decoded.includes('\n')) {
        return '`' + decoded.replace(/`/g, '\\`') + '`';
    }
    return JSON.stringify(decoded);
}

function replaceCalls(code, decoder) {
    const callPattern = /_0x[a-f0-9]+\s*\(\s*(0x[a-f0-9]+|\d+)\s*,\s*['"]([^'"]+)['"]\s*\)/gi;
    const replacements = new Map();
    let match;

    while ((match = callPattern.exec(code)) !== null) {
        const full = match[0];
        if (replacements.has(full)) continue;

        const index = match[1].startsWith('0x') ? parseInt(match[1], 16) : parseInt(match[1], 10);
        const key = match[2];

        try {
            const decoded = decoder(index, key);
            if (typeof decoded === 'string') {
                replacements.set(full, literalFor(decoded));
            }
        } catch {
            /* ignore individual decode errors */
        }
    }

    let replacedCount = 0;
    for (const [call, literal] of replacements) {
        const newCode = code.split(call).join(literal);
        if (newCode !== code) {
            replacedCount++;
            code = newCode;
        }
    }
    return { code, replacedCount, found: replacements.size };
}

function replaceWithMap(code, relPath) {
    const mapPath = mapPaths[relPath];
    if (!mapPath || !fs.existsSync(mapPath)) {
        return { code, replacedCount: 0, entries: 0 };
    }
    const decodeMap = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
    let replacedCount = 0;
    for (const [pattern, decoded] of Object.entries(decodeMap)) {
        const literal = literalFor(decoded);
        const newCode = code.split(pattern).join(literal);
        if (newCode !== code) {
            replacedCount++;
            code = newCode;
        }
    }
    return { code, replacedCount, entries: Object.keys(decodeMap).length };
}

function cleanDecoderBlocks(code) {
    // 保留原始函数，避免因匹配不准破坏结构
    return code;
}

function processFile(relPath) {
    const inputPath = path.join(inputBase, relPath);
    const outputPath = path.join(outputBase, relPath);

    if (!fs.existsSync(inputPath)) {
        console.warn(`跳过缺失文件: ${relPath}`);
        return;
    }

    let code = fs.readFileSync(inputPath, 'utf8');
    console.log(`\n==== 处理 ${relPath} ====`);

    const mapResult = replaceWithMap(code, relPath);
    if (mapResult.entries > 0) {
        console.log(`  预置映射 ${mapResult.entries} 条，替换 ${mapResult.replacedCount} 处`);
        code = mapResult.code;
    }

    const decoder = buildDecoder(code);
    if (!decoder) {
        console.warn('  未找到可用的解码器，直接美化原始代码');
    } else {
        const result = replaceCalls(code, decoder);
        console.log(`  找到 ${result.found} 个唯一调用，成功替换 ${result.replacedCount} 处`);
        code = result.code;
    }

    code = cleanDecoderBlocks(code);
    code = beautify(code, { indent_size: 4, max_preserve_newlines: 2, end_with_newline: true });

    ensureDir(path.dirname(outputPath));
    fs.writeFileSync(outputPath, code, 'utf8');
    console.log(`  输出: ${outputPath}`);
}

function main() {
    targets.forEach(processFile);
    console.log('\n全部处理完成。');
}

main();
