/**
 * Gemini Code Handler
 *
 * Handles Gemini CLI streaming for web clients.
 */
import { WebSocket } from 'ws';
import { spawn, exec } from 'child_process';
import { homedir, tmpdir } from 'os';
import { promises as fs } from 'fs';
import * as path from 'path';
import { existsSync } from 'fs';
// Active Gemini processes
const activeGeminiProcesses = new Map();
// Check Gemini CLI availability
function checkGeminiCLI() {
    return new Promise((resolve) => {
        const isWindows = process.platform === 'win32';
        if (isWindows) {
            exec('where gemini', { shell: process.env.ComSpec || 'cmd.exe', timeout: 5000 }, (error, stdout) => {
                if (!error && stdout.trim()) {
                    resolve(true);
                    return;
                }
                exec('where gcloud', { shell: process.env.ComSpec || 'cmd.exe' }, (error2) => {
                    resolve(!error2);
                });
            });
        }
        else {
            exec('which gemini', (error, stdout) => {
                if (!error && stdout.trim()) {
                    resolve(true);
                }
                else {
                    exec('which gcloud', (error2) => {
                        resolve(!error2);
                    });
                }
            });
        }
    });
}
// Get Gemini command
async function getGeminiCommand() {
    const isWindows = process.platform === 'win32';
    return new Promise((resolve) => {
        if (isWindows) {
            exec('where gemini', { shell: process.env.ComSpec || 'cmd.exe' }, (error, stdout) => {
                if (!error && stdout.trim()) {
                    resolve(stdout.trim().split('\n')[0].trim());
                }
                else {
                    resolve('gcloud');
                }
            });
        }
        else {
            exec('which gemini', (error) => {
                if (!error) {
                    resolve('gemini');
                }
                else {
                    resolve('gcloud');
                }
            });
        }
    });
}
// Clean CLI output
function cleanCliOutput(text) {
    if (!text)
        return text;
    return text
        .replace(/\x1b\[[0-9;]*m/g, '')
        .replace(/\x1b\[\?25[hl]/g, '')
        .replace(/\x1b\[[12][JK]/g, '')
        .replace(/\x1b\[[0-9]+[ABCDEFG]/g, '')
        .replace(/\x1b\[[0-9]*K/g, '')
        .replace(/\r\n/g, '\n')
        .replace(/\n{5,}/g, '\n\n\n');
}
// Gemini Code handler
export function setupGeminiCodeHandler(ws, sessionId) {
    return (msg) => {
        const { type, id, requestId, method, args } = msg;
        if (method === 'geminiCode:streamMessage') {
            handleStreamMessage(ws, requestId, args);
            return;
        }
        if (method === 'geminiCode:cancelStream') {
            handleCancelStream(ws, id, requestId);
            return;
        }
        if (method === 'geminiCode:checkAvailability') {
            handleCheckAvailability(ws, id);
            return;
        }
        if (method === 'geminiCode:getContext') {
            handleGetContext(ws, id, args);
            return;
        }
        ws.send(JSON.stringify({ type: 'error', id, error: `Unknown geminiCode method: ${method}` }));
    };
}
async function handleStreamMessage(ws, requestId, args) {
    const options = args[0] || {};
    const { message, files = [], images = [], cwd } = options;
    const workingDir = cwd || homedir();
    if (!message || !message.trim()) {
        ws.send(JSON.stringify({ type: 'streamError', requestId, error: '消息内容为空' }));
        return;
    }
    const cliAvailable = await checkGeminiCLI();
    if (!cliAvailable) {
        ws.send(JSON.stringify({
            type: 'streamError',
            requestId,
            error: 'Gemini CLI 未安装。请安装 Gemini CLI 或 Google Cloud CLI。\n\n安装命令: npm install -g @google/gemini-cli'
        }));
        return;
    }
    const command = await getGeminiCommand();
    if (command === 'gcloud') {
        ws.send(JSON.stringify({
            type: 'streamError',
            requestId,
            error: '未找到 Gemini CLI。请安装: npm install -g @google/gemini-cli'
        }));
        return;
    }
    const isWindows = process.platform === 'win32';
    // Save base64 images
    const tempImagePaths = [];
    for (let i = 0; i < images.length; i++) {
        try {
            const base64Data = images[i].replace(/^data:image\/\w+;base64,/, '');
            const buffer = Buffer.from(base64Data, 'base64');
            const ext = images[i].match(/data:image\/(\w+);/)?.[1] || 'png';
            const tempPath = path.join(tmpdir(), `gemini-image-${Date.now()}-${i}.${ext}`);
            await fs.writeFile(tempPath, buffer);
            tempImagePaths.push(tempPath);
        }
        catch (err) {
            console.error('[GeminiCode] Failed to save image:', err);
        }
    }
    // Separate files
    const localImagePaths = [];
    const otherFiles = [];
    for (const file of files) {
        const ext = path.extname(file).toLowerCase();
        if (['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg'].includes(ext)) {
            localImagePaths.push(file);
        }
        else {
            otherFiles.push(file);
        }
    }
    // Build message
    let fullMessage = message;
    if (otherFiles.length > 0) {
        fullMessage += '\n\n[系统：用户附加了以下文件路径]';
        otherFiles.forEach(file => {
            fullMessage += `\n- ${file}`;
        });
    }
    if (localImagePaths.length > 0) {
        fullMessage += '\n\n[系统：用户附加了以下图片路径]';
        localImagePaths.forEach(imgPath => {
            fullMessage += `\n- ${imgPath}`;
        });
    }
    // Build args
    const geminiArgs = ['--approval-mode', 'auto_edit'];
    // Add image args
    localImagePaths.forEach(imgPath => {
        if (existsSync(imgPath)) {
            geminiArgs.push('--image', imgPath);
        }
    });
    tempImagePaths.forEach(imgPath => {
        geminiArgs.push('--image', imgPath);
    });
    // Add file args
    otherFiles.forEach(filePath => {
        if (existsSync(filePath)) {
            geminiArgs.push('--file', filePath);
        }
    });
    // Send start
    ws.send(JSON.stringify({ type: 'streamStart', requestId }));
    // Spawn Gemini
    let child;
    if (isWindows) {
        const resolvedCwd = path.resolve(workingDir);
        const escapedArgs = geminiArgs.map(arg => {
            if (arg.includes(' ') || arg.includes('"') || /[^\x00-\x7F]/.test(arg)) {
                return `"${arg.replace(/"/g, '\\"')}"`;
            }
            return arg;
        });
        const cmdLine = [command, ...escapedArgs].join(' ');
        child = spawn(cmdLine, {
            cwd: resolvedCwd,
            shell: true,
            stdio: ['pipe', 'pipe', 'pipe'],
            env: { ...process.env, FORCE_COLOR: '0', CI: '1' },
        });
    }
    else {
        child = spawn(command, geminiArgs, {
            cwd: workingDir,
            env: { ...process.env, FORCE_COLOR: '0', CI: '1' },
        });
    }
    activeGeminiProcesses.set(requestId, child);
    let hasOutput = false;
    let errorOutput = '';
    const timeout = setTimeout(() => {
        child.kill('SIGTERM');
        ws.send(JSON.stringify({ type: 'streamError', requestId, error: 'Gemini CLI 响应超时（5分钟）' }));
    }, 300000);
    child.stdout.on('data', (data) => {
        const chunk = data.toString();
        hasOutput = true;
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ type: 'streamData', requestId, data: chunk }));
        }
    });
    child.stderr.on('data', (data) => {
        const chunk = data.toString();
        errorOutput += chunk;
        hasOutput = true;
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ type: 'streamData', requestId, data: chunk }));
        }
    });
    child.on('close', async (code) => {
        clearTimeout(timeout);
        activeGeminiProcesses.delete(requestId);
        for (const tempPath of tempImagePaths) {
            try {
                await fs.unlink(tempPath);
            }
            catch { /* ignore */ }
        }
        await new Promise(r => setTimeout(r, 100));
        if (ws.readyState === WebSocket.OPEN) {
            if (code === 0 || code === null || hasOutput) {
                ws.send(JSON.stringify({ type: 'streamEnd', requestId }));
            }
            else {
                if (errorOutput.includes('API key') || errorOutput.includes('authentication')) {
                    ws.send(JSON.stringify({
                        type: 'streamError',
                        requestId,
                        error: 'Gemini API Key 无效或未配置。\n\n解决方法：\n1. 运行 `gemini login` 登录\n2. 或设置 GEMINI_API_KEY 环境变量'
                    }));
                }
                else {
                    ws.send(JSON.stringify({ type: 'streamError', requestId, error: cleanCliOutput(errorOutput) || 'Gemini CLI 异常退出' }));
                }
            }
        }
    });
    child.on('error', (error) => {
        clearTimeout(timeout);
        activeGeminiProcesses.delete(requestId);
        for (const tempPath of tempImagePaths) {
            try {
                fs.unlink(tempPath);
            }
            catch { /* ignore */ }
        }
        if (ws.readyState === WebSocket.OPEN) {
            if (error.message?.includes('ENOENT')) {
                ws.send(JSON.stringify({
                    type: 'streamError',
                    requestId,
                    error: `找不到 Gemini CLI 命令: ${command}\n\n请确保已安装并添加到 PATH 环境变量。\n安装命令: npm install -g @google/gemini-cli`
                }));
            }
            else {
                ws.send(JSON.stringify({ type: 'streamError', requestId, error: `启动 Gemini CLI 失败: ${error.message}` }));
            }
        }
    });
    // Send message to stdin
    child.stdin.write(fullMessage);
    child.stdin.end();
}
function handleCancelStream(ws, id, requestId) {
    const child = activeGeminiProcesses.get(requestId);
    if (child) {
        child.kill('SIGTERM');
        activeGeminiProcesses.delete(requestId);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    else {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'No active stream' } }));
    }
}
async function handleCheckAvailability(ws, id) {
    const available = await checkGeminiCLI();
    ws.send(JSON.stringify({ type: 'response', id, result: { available } }));
}
async function handleGetContext(ws, id, args) {
    const cwd = args[0] || homedir();
    const cliAvailable = await checkGeminiCLI();
    if (!cliAvailable) {
        ws.send(JSON.stringify({
            type: 'response',
            id,
            result: { success: false, error: 'Gemini CLI 未安装' }
        }));
        return;
    }
    ws.send(JSON.stringify({
        type: 'response',
        id,
        result: { success: true, context: { cwd } }
    }));
}
//# sourceMappingURL=gemini-code.js.map