import { spawn } from 'child_process';
import path from 'path';
import fs from 'fs';
import { promises as fsPromises } from 'fs';
import { fileURLToPath } from 'url';
import os from 'os';
import { promisify } from 'util';
import { exec } from 'child_process';
import { TerminalSessionManager } from './TerminalSessionManager.js';
import { ptyManager } from '../../utils/ptyManager.js';
import { buildUtf8LocaleEnv } from '../../utils/filenameEncoding.js';
const execAsync = promisify(exec);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export class TerminalManager {
    constructor(io, logger, configManager) {
        this.sessions = new Map();
        this.io = io;
        this.logger = logger;
        this.configManager = configManager;
        this.sessionManager = new TerminalSessionManager(logger);
        this.ptyPath = '';
    }
    async initialize() {
        await this.sessionManager.initialize();
        try {
            this.ptyPath = await ptyManager.getPtyPath();
            this.logger.info(`终端管理器初始化完成，PTY路径: ${this.ptyPath}`);
        }
        catch (error) {
            this.logger.error(`无法找到 PTY 文件: ${error.message}`);
            try {
                const ptyFileName = ptyManager.getBinaryName();
                this.ptyPath = path.join(process.cwd(), 'data', 'lib', ptyFileName);
                this.logger.warn(`使用备用 PTY 路径: ${this.ptyPath}`);
            }
            catch (nameError) {
                this.logger.error(`无法获取 PTY 文件名: ${nameError.message}`);
            }
        }
    }
    async createPty(socket, data) {
        try {
            const { sessionId, name, cols, rows, workingDirectory = process.cwd(), enableStreamForward = false, programPath, autoCloseOnForwardExit = false, terminalUser } = data;
            const sessionName = name || `终端会话 ${sessionId.slice(-8)}`;
            const terminalConfig = this.configManager.getTerminalConfig();
            const defaultUser = terminalUser || terminalConfig.defaultUser;
            if (os.platform() === 'linux' && defaultUser && defaultUser.trim() !== '' && defaultUser !== 'root') {
                try {
                    await this.setDirectoryPermissions777(workingDirectory);
                    this.logger.info(`已为非root用户 ${defaultUser} 设置工作目录权限为777: ${workingDirectory}`);
                }
                catch (error) {
                    this.logger.warn(`设置工作目录权限失败: ${error}`);
                }
            }
            if (enableStreamForward && os.platform() !== 'win32') {
                this.logger.warn(`输出流转发功能仅在Windows平台支持，当前平台: ${os.platform()}`);
                socket.emit('terminal-error', {
                    sessionId,
                    error: '输出流转发功能仅在Windows平台支持'
                });
                return;
            }
            if (enableStreamForward && !programPath) {
                this.logger.warn(`启用输出流转发时必须提供程序启动命令`);
                socket.emit('terminal-error', {
                    sessionId,
                    error: '启用输出流转发时必须提供程序启动命令'
                });
                return;
            }
            if (enableStreamForward && programPath) {
                const commandLine = programPath.trim();
                let executablePath;
                if (commandLine.startsWith('"')) {
                    const endQuoteIndex = commandLine.indexOf('"', 1);
                    if (endQuoteIndex === -1) {
                        this.logger.warn(`未找到匹配的引号: ${commandLine}`);
                        socket.emit('terminal-error', {
                            sessionId,
                            error: '未找到匹配的引号'
                        });
                        return;
                    }
                    executablePath = commandLine.substring(1, endQuoteIndex);
                }
                else {
                    const parts = commandLine.split(/\s+/);
                    executablePath = parts[0];
                }
                if (!path.isAbsolute(executablePath)) {
                    this.logger.warn(`可执行文件路径必须是绝对路径: ${executablePath}`);
                    socket.emit('terminal-error', {
                        sessionId,
                        error: '可执行文件路径必须是绝对路径'
                    });
                    return;
                }
            }
            this.logger.info(`创建PTY会话: ${sessionId} (${sessionName}), 大小: ${cols}x${rows}`);
            if (this.sessions.has(sessionId)) {
                this.logger.warn(`会话 ${sessionId} 已存在，先关闭旧会话`);
                this.closePty(socket, { sessionId });
            }
            const args = [
                '-dir', workingDirectory,
                '-size', `${cols},${rows}`,
                '-coder', 'UTF-8'
            ];
            const terminalEnv = buildUtf8LocaleEnv({
                ...process.env,
                TERM: 'xterm-256color',
                COLORTERM: 'truecolor'
            });
            if (os.platform() === 'win32') {
                args.push('-cmd', JSON.stringify(['powershell.exe']));
            }
            else {
                if (defaultUser && defaultUser.trim() !== '') {
                    const userExists = await this.checkUserExists(defaultUser);
                    if (userExists) {
                        const sudoExists = await this.checkCommandExists('sudo');
                        if (sudoExists) {
                            args.push('-cmd', JSON.stringify([
                                'sudo', '-u', defaultUser,
                                'env',
                                'LANG=zh_CN.UTF-8',
                                'LANGUAGE=zh_CN:zh',
                                'LC_ALL=zh_CN.UTF-8',
                                'LC_CTYPE=zh_CN.UTF-8',
                                '/bin/bash', '-c',
                                `cd "${workingDirectory}" && exec /bin/bash --login`
                            ]));
                            this.logger.info(`使用sudo切换到默认用户启动终端: ${defaultUser}，工作目录: ${workingDirectory}`);
                        }
                        else {
                            const suExists = await this.checkCommandExists('su');
                            if (suExists) {
                                args.push('-cmd', JSON.stringify([
                                    'su', defaultUser, '-c',
                                    'export LANG=zh_CN.UTF-8 LANGUAGE=zh_CN:zh LC_ALL=zh_CN.UTF-8 LC_CTYPE=zh_CN.UTF-8; ' +
                                        `cd "${workingDirectory}" && exec /bin/bash --login`
                                ]));
                                this.logger.info(`使用su切换到默认用户启动终端: ${defaultUser}，工作目录: ${workingDirectory}`);
                            }
                            else {
                                this.logger.warn(`系统中既没有sudo也没有su命令，无法切换到用户 '${defaultUser}'，使用当前用户`);
                                args.push('-cmd', JSON.stringify(['/bin/bash', '--login']));
                            }
                        }
                    }
                    else {
                        this.logger.warn(`配置的默认用户 '${defaultUser}' 不存在，使用默认bash`);
                        args.push('-cmd', JSON.stringify(['/bin/bash', '--login']));
                    }
                }
                else {
                    args.push('-cmd', JSON.stringify(['/bin/bash', '--login']));
                }
            }
            this.logger.info(`启动PTY进程: ${this.ptyPath} ${args.join(' ')}`);
            const ptyProcess = spawn(this.ptyPath, args, {
                stdio: ['pipe', 'pipe', 'pipe'],
                cwd: workingDirectory,
                env: terminalEnv,
                detached: os.platform() !== 'win32'
            });
            this.logger.info(`PTY进程已启动，PID: ${ptyProcess.pid}`);
            const session = {
                id: sessionId,
                name: sessionName,
                process: ptyProcess,
                socket,
                workingDirectory,
                createdAt: new Date(),
                lastActivity: new Date(),
                outputBuffer: [],
                enableStreamForward,
                programPath,
                autoCloseOnForwardExit
            };
            this.sessions.set(sessionId, session);
            this.sessionManager.saveSession({
                id: sessionId,
                name: sessionName,
                workingDirectory,
                createdAt: session.createdAt,
                lastActivity: session.lastActivity,
                isActive: true
            }).catch(error => {
                this.logger.error(`保存会话到配置文件失败: ${sessionId}`, error);
            });
            ptyProcess.stdout?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                this.logger.debug(`PTY输出 ${sessionId}: ${JSON.stringify(output)}`);
                socket.emit('terminal-output', {
                    sessionId,
                    data: output
                });
            });
            ptyProcess.stderr?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                this.logger.warn(`PTY错误输出 ${sessionId}: ${JSON.stringify(output)}`);
                socket.emit('terminal-output', {
                    sessionId,
                    data: output
                });
            });
            ptyProcess.on('exit', (code, signal) => {
                this.logger.info(`PTY进程退出: ${sessionId}, 退出码: ${code}, 信号: ${signal}`);
                if (code === 0 && (Date.now() - session.createdAt.getTime()) < 1000) {
                    this.logger.warn(`PTY进程启动后立即退出，可能是用户切换命令有问题: ${sessionId}`);
                    this.logger.warn(`使用的命令参数: ${JSON.stringify(args)}`);
                    if (defaultUser && defaultUser.trim() !== '' && !session.fallbackRetried) {
                        this.logger.info(`尝试使用当前用户重新启动终端: ${sessionId}`);
                        session.fallbackRetried = true;
                        setTimeout(() => {
                            this.createPtyFallback(sessionId, sessionName, workingDirectory, socket, enableStreamForward, programPath, autoCloseOnForwardExit);
                        }, 100);
                        return;
                    }
                }
                if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                    this.logger.info(`PTY退出时清理输出流转发进程: ${sessionId}`);
                    this.forceKillProcess(session.streamForwardProcess, '输出流转发进程', () => {
                        session.streamForwardProcess = undefined;
                    });
                }
                socket.emit('terminal-exit', {
                    sessionId,
                    code: code || 0,
                    signal
                });
                this.sessions.delete(sessionId);
                this.sessionManager.removeSession(sessionId).catch(error => {
                    this.logger.error(`PTY退出时从配置文件删除会话失败: ${sessionId}`, error);
                });
            });
            ptyProcess.on('error', (error) => {
                this.logger.error(`PTY进程错误 ${sessionId}:`, error);
                if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                    this.logger.info(`PTY错误时清理输出流转发进程: ${sessionId}`);
                    this.forceKillProcess(session.streamForwardProcess, '输出流转发进程', () => {
                        session.streamForwardProcess = undefined;
                    });
                }
                socket.emit('terminal-error', {
                    sessionId,
                    error: error.message
                });
                this.sessions.delete(sessionId);
                this.sessionManager.removeSession(sessionId).catch(error => {
                    this.logger.error(`PTY错误时从配置文件删除会话失败: ${sessionId}`, error);
                });
            });
            if (os.platform() !== 'win32' && ptyProcess.pid) {
                try {
                    process.kill(-ptyProcess.pid, 0);
                    this.logger.info(`PTY进程组设置成功: ${ptyProcess.pid}`);
                }
                catch (error) {
                    this.logger.warn(`设置PTY进程组失败: ${error}`);
                }
            }
            if (enableStreamForward && programPath) {
                this.startStreamForwardProcess(session, programPath);
            }
            socket.emit('pty-created', {
                sessionId,
                workingDirectory
            });
            this.logger.info(`PTY会话创建成功: ${sessionId}`);
            setTimeout(() => {
                if (ptyProcess.stdin && !ptyProcess.stdin.destroyed) {
                    ptyProcess.stdin.write('\r');
                }
            }, 500);
        }
        catch (error) {
            this.logger.error(`创建PTY会话失败:`, error);
            socket.emit('terminal-error', {
                sessionId: data.sessionId,
                error: error instanceof Error ? error.message : '未知错误'
            });
        }
    }
    forceKillProcess(process, processName, onKilled) {
        if (!process || process.killed) {
            onKilled?.();
            return;
        }
        const pid = process.pid;
        this.logger.info(`开始强制终止${processName}，PID: ${pid}`);
        const onExit = () => {
            this.logger.info(`${processName}已退出: ${pid}`);
            onKilled?.();
        };
        process.once('exit', onExit);
        try {
            if (os.platform() !== 'win32' && pid) {
                try {
                    process.kill(-pid, 'SIGINT');
                    this.logger.info(`已向${processName}进程组发送SIGINT信号: -${pid}`);
                }
                catch (error) {
                    this.logger.warn(`向进程组发送信号失败，尝试向单个进程发送: ${error}`);
                    process.kill('SIGINT');
                    this.logger.info(`已向${processName}发送SIGINT信号: ${pid}`);
                }
            }
            else {
                process.kill('SIGINT');
                this.logger.info(`已向${processName}发送SIGINT信号: ${pid}`);
            }
            setTimeout(() => {
                if (!process.killed) {
                    this.logger.warn(`${processName}未响应SIGINT信号，尝试SIGTERM: ${pid}`);
                    try {
                        if (os.platform() !== 'win32' && pid) {
                            try {
                                process.kill(-pid, 'SIGTERM');
                                this.logger.info(`已向${processName}进程组发送SIGTERM信号: -${pid}`);
                            }
                            catch (error) {
                                process.kill('SIGTERM');
                                this.logger.info(`已向${processName}发送SIGTERM信号: ${pid}`);
                            }
                        }
                        else {
                            process.kill('SIGTERM');
                        }
                    }
                    catch (error) {
                        this.logger.warn(`发送SIGTERM信号失败:`, error);
                    }
                    setTimeout(() => {
                        if (!process.killed) {
                            this.logger.warn(`${processName}未响应SIGTERM信号，强制杀死: ${pid}`);
                            try {
                                if (os.platform() !== 'win32' && pid) {
                                    try {
                                        process.kill(-pid, 'SIGKILL');
                                        this.logger.info(`已向${processName}进程组发送SIGKILL信号: -${pid}`);
                                    }
                                    catch (error) {
                                        process.kill('SIGKILL');
                                        this.logger.info(`已向${processName}发送SIGKILL信号: ${pid}`);
                                    }
                                }
                                else {
                                    process.kill('SIGKILL');
                                }
                            }
                            catch (error) {
                                this.logger.error(`强制杀死进程失败:`, error);
                                if (os.platform() === 'win32' && pid) {
                                    exec(`taskkill /F /PID ${pid}`, (error) => {
                                        if (error) {
                                            this.logger.error(`taskkill命令执行失败:`, error);
                                        }
                                        else {
                                            this.logger.info(`使用taskkill成功终止${processName}: ${pid}`);
                                        }
                                        if (!process.killed) {
                                            process.removeListener('exit', onExit);
                                            onKilled?.();
                                        }
                                    });
                                }
                                else {
                                    if (pid) {
                                        exec(`pkill -9 -g ${pid}`, (error) => {
                                            if (error) {
                                                this.logger.error(`pkill命令执行失败:`, error);
                                            }
                                            else {
                                                this.logger.info(`使用pkill成功终止${processName}进程组: ${pid}`);
                                            }
                                            if (!process.killed) {
                                                process.removeListener('exit', onExit);
                                                onKilled?.();
                                            }
                                        });
                                    }
                                    else {
                                        process.removeListener('exit', onExit);
                                        onKilled?.();
                                    }
                                }
                            }
                        }
                    }, 2000);
                }
            }, 2000);
        }
        catch (error) {
            this.logger.error(`强制终止${processName}失败:`, error);
            process.removeListener('exit', onExit);
            onKilled?.();
        }
    }
    restartStreamForwardProcess(sessionId) {
        const session = this.sessions.get(sessionId);
        if (!session || !session.enableStreamForward || !session.programPath) {
            this.logger.warn(`无法重启转发进程: 会话不存在或未启用输出流转发: ${sessionId}`);
            return false;
        }
        if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
            this.forceKillProcess(session.streamForwardProcess, '输出流转发进程', () => {
                session.streamForwardProcess = undefined;
                this.startStreamForwardProcess(session, session.programPath);
            });
        }
        else {
            this.startStreamForwardProcess(session, session.programPath);
        }
        return true;
    }
    startStreamForwardProcess(session, programPath) {
        try {
            this.logger.info(`启动输出流转发进程: ${programPath}`);
            const commandLine = programPath.trim();
            let executablePath;
            let args;
            if (commandLine.startsWith('"')) {
                const endQuoteIndex = commandLine.indexOf('"', 1);
                if (endQuoteIndex === -1) {
                    throw new Error('未找到匹配的引号');
                }
                executablePath = commandLine.substring(1, endQuoteIndex);
                const remainingArgs = commandLine.substring(endQuoteIndex + 1).trim();
                args = remainingArgs ? remainingArgs.split(/\s+/) : [];
            }
            else {
                const parts = commandLine.split(/\s+/);
                executablePath = parts[0];
                args = parts.slice(1);
            }
            this.logger.info(`可执行文件路径: ${executablePath}`);
            this.logger.info(`参数列表: ${JSON.stringify(args)}`);
            let forwardProcess;
            if (os.platform() === 'win32' && this.ptyPath) {
                const ptyArgs = [
                    '-dir', session.workingDirectory,
                    '-size', '100,30',
                    '-coder', 'UTF-8',
                    '-cmd', JSON.stringify([executablePath, ...args])
                ];
                this.logger.info(`使用PTY包装转发进程以避免stdout缓冲: ${this.ptyPath}`);
                forwardProcess = spawn(this.ptyPath, ptyArgs, {
                    stdio: ['pipe', 'pipe', 'pipe'],
                    cwd: session.workingDirectory,
                    env: {
                        ...process.env,
                        TERM: 'xterm-256color',
                        COLORTERM: 'truecolor'
                    }
                });
            }
            else {
                forwardProcess = spawn(executablePath, args, {
                    stdio: ['pipe', 'pipe', 'pipe'],
                    cwd: session.workingDirectory,
                    env: {
                        ...process.env,
                        TERM: 'xterm-256color',
                        COLORTERM: 'truecolor'
                    },
                    detached: os.platform() !== 'win32'
                });
            }
            session.streamForwardProcess = forwardProcess;
            this.logger.info(`输出流转发进程已启动，PID: ${forwardProcess.pid}`);
            let startupMessage = `\r\n[输出流转发进程已启动，PID: ${forwardProcess.pid}]\r\n`;
            startupMessage += `[程序路径: ${executablePath}]\r\n`;
            if (session.autoCloseOnForwardExit) {
                startupMessage += `[注意: 转发进程异常退出时将自动关闭终端会话]\r\n`;
            }
            startupMessage += `[可用命令: restart-forward (重启转发进程), session-status (查看状态)]\r\n`;
            session.socket.emit('terminal-output', {
                sessionId: session.id,
                data: startupMessage
            });
            forwardProcess.stdout?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                this.logger.debug(`转发进程输出 ${session.id}: ${JSON.stringify(output)}`);
                session.socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: output
                });
            });
            forwardProcess.stderr?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                this.logger.warn(`转发进程错误输出 ${session.id}: ${JSON.stringify(output)}`);
                session.socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: output
                });
            });
            forwardProcess.on('exit', (code, signal) => {
                this.logger.info(`转发进程退出: ${session.id}, 退出码: ${code}, 信号: ${signal}`);
                let exitMessage;
                if (signal) {
                    exitMessage = `\r\n[转发进程被信号终止: ${signal}]\r\n`;
                }
                else if (code === null) {
                    exitMessage = `\r\n[转发进程异常退出]\r\n`;
                }
                else if (code === 0) {
                    exitMessage = `\r\n[转发进程正常退出]\r\n`;
                }
                else {
                    exitMessage = `\r\n[转发进程退出，错误码: ${code}]\r\n`;
                }
                session.socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: exitMessage
                });
                session.streamForwardProcess = undefined;
                if (session.autoCloseOnForwardExit) {
                    session.socket.emit('terminal-output', {
                        sessionId: session.id,
                        data: `\r\n[转发进程已退出，正在关闭终端会话...]\r\n`
                    });
                    setTimeout(() => {
                        this.closePty(session.socket, { sessionId: session.id });
                    }, 2000);
                }
                else {
                    if (code !== 0 || signal) {
                        session.socket.emit('terminal-output', {
                            sessionId: session.id,
                            data: `\r\n[提示: 输入 'restart-forward' 可重启转发进程]\r\n`
                        });
                    }
                }
            });
            forwardProcess.on('error', (error) => {
                this.logger.error(`转发进程错误 ${session.id}:`, error);
                let errorMessage;
                if (error.code === 'ENOENT') {
                    errorMessage = `\r\n[转发进程启动失败: 找不到可执行文件]\r\n`;
                }
                else if (error.code === 'EACCES') {
                    errorMessage = `\r\n[转发进程启动失败: 权限不足]\r\n`;
                }
                else if (error.code === 'EMFILE' || error.code === 'ENFILE') {
                    errorMessage = `\r\n[转发进程启动失败: 系统资源不足]\r\n`;
                }
                else {
                    errorMessage = `\r\n[转发进程错误: ${error.message}]\r\n`;
                }
                session.socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: errorMessage
                });
                session.streamForwardProcess = undefined;
            });
        }
        catch (error) {
            this.logger.error(`启动输出流转发进程失败:`, error);
            session.socket.emit('terminal-output', {
                sessionId: session.id,
                data: `\r\n[启动转发进程失败: ${error instanceof Error ? error.message : '未知错误'}]\r\n`
            });
        }
    }
    handleInput(socket, data) {
        try {
            const { sessionId, data: inputData } = data;
            const session = this.sessions.get(sessionId);
            if (!session) {
                this.logger.warn(`会话不存在: ${sessionId}`);
                socket.emit('terminal-error', {
                    sessionId,
                    error: '会话不存在'
                });
                return;
            }
            if (session.disconnected && socket.connected !== undefined) {
                session.disconnected = false;
                session.disconnectedAt = undefined;
                session.socket = socket;
                this.logger.info(`会话 ${sessionId} 重新连接成功`);
            }
            session.lastActivity = new Date();
            if (inputData.trim() === 'restart-forward') {
                if (session.enableStreamForward && session.programPath) {
                    session.socket.emit('terminal-output', {
                        sessionId: session.id,
                        data: `\r\n[正在重启输出流转发进程...]\r\n`
                    });
                    const success = this.restartStreamForwardProcess(sessionId);
                    if (!success) {
                        session.socket.emit('terminal-output', {
                            sessionId: session.id,
                            data: `\r\n[重启转发进程失败]\r\n`
                        });
                    }
                }
                else {
                    session.socket.emit('terminal-output', {
                        sessionId: session.id,
                        data: `\r\n[当前会话未启用输出流转发]\r\n`
                    });
                }
                return;
            }
            if (inputData.trim() === 'session-status') {
                const status = this.getSessionStatusInfo(session);
                session.socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: status
                });
                return;
            }
            const controlChar = this.detectControlCharacter(inputData);
            if (controlChar) {
                this.logger.info(`检测到控制字符: ${controlChar.name} (${controlChar.code}) - ${sessionId}`);
                if (controlChar.signal === 'EOF' || controlChar.signal === 'KILL_LINE' || controlChar.signal === 'CLEAR') {
                    this.logger.info(`直接传递控制字符 ${controlChar.name} 到 PTY 进程: ${sessionId}`);
                    if (session.process.stdin && !session.process.stdin.destroyed) {
                        session.process.stdin.write(inputData);
                    }
                    return;
                }
                if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                    const pid = session.streamForwardProcess.pid;
                    this.logger.info(`向输出流转发进程(PID: ${pid})及其子进程发送${controlChar.name}信号...`);
                    if (os.platform() === 'win32') {
                        if (controlChar.signal === 'SIGINT') {
                            exec(`taskkill /PID ${pid} /T`, (err) => {
                                if (err) {
                                    this.logger.error(`使用 taskkill /T 终止进程树 PID: ${pid} 失败:`, err);
                                    try {
                                        session.streamForwardProcess.kill('SIGINT');
                                    }
                                    catch (killError) {
                                        this.logger.error(`后备的 kill SIGINT 信号也失败了:`, killError);
                                    }
                                }
                                else {
                                    this.logger.info(`成功通过 taskkill /T 向进程树 PID: ${pid} 发送关闭信号`);
                                }
                            });
                        }
                        else {
                            if (typeof controlChar.signal === 'string' && controlChar.signal.startsWith('SIG')) {
                                try {
                                    session.streamForwardProcess.kill(controlChar.signal);
                                }
                                catch (error) {
                                    this.logger.error(`发送${controlChar.signal}信号失败:`, error);
                                }
                            }
                            else {
                                this.logger.warn(`Windows下不支持的信号类型: ${controlChar.signal}`);
                            }
                        }
                    }
                    else {
                        if (typeof controlChar.signal === 'string' && controlChar.signal.startsWith('SIG')) {
                            try {
                                process.kill(-pid, controlChar.signal);
                                this.logger.info(`成功向进程组 -${pid} 发送 ${controlChar.signal} 信号`);
                            }
                            catch (error) {
                                this.logger.error(`向进程组 -${pid} 发送${controlChar.signal}失败，将只发送给主进程:`, error);
                                try {
                                    session.streamForwardProcess.kill(controlChar.signal);
                                }
                                catch (killError) {
                                    this.logger.error(`向主进程发送${controlChar.signal}失败:`, killError);
                                }
                            }
                        }
                        else {
                            this.logger.warn(`Linux/macOS下不支持的信号类型: ${controlChar.signal}`);
                        }
                    }
                }
                else {
                    this.logger.info(`向 PTY 进程发送 ${controlChar.name}: ${sessionId}`);
                    if (session.process.stdin && !session.process.stdin.destroyed) {
                        session.process.stdin.write(inputData);
                    }
                }
                return;
            }
            if (session.process.stdin && !session.process.stdin.destroyed) {
                session.process.stdin.write(inputData);
            }
            else {
                this.logger.warn(`PTY进程stdin不可用: ${sessionId}`);
            }
            if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                if (session.streamForwardProcess.stdin && !session.streamForwardProcess.stdin.destroyed) {
                    session.streamForwardProcess.stdin.write(inputData);
                }
            }
        }
        catch (error) {
            this.logger.error(`处理终端输入失败:`, error);
            socket.emit('terminal-error', {
                sessionId: data.sessionId,
                error: error instanceof Error ? error.message : '未知错误'
            });
        }
    }
    resizeTerminal(socket, data) {
        try {
            const { sessionId, cols, rows } = data;
            const session = this.sessions.get(sessionId);
            if (!session) {
                this.logger.warn(`会话不存在: ${sessionId}`);
                return;
            }
            this.logger.info(`调整终端大小: ${sessionId}, ${cols}x${rows}`);
            session.lastActivity = new Date();
            try {
                if (session.process.pid && !session.process.killed) {
                    process.kill(session.process.pid, 'SIGWINCH');
                    this.logger.info(`已发送SIGWINCH信号调整终端大小: ${sessionId}, ${cols}x${rows}`);
                }
            }
            catch (signalError) {
                this.logger.debug(`发送SIGWINCH信号失败: ${signalError}`);
            }
            session.socket.emit('terminal-resized', {
                sessionId,
                cols,
                rows
            });
        }
        catch (error) {
            this.logger.error(`调整终端大小失败:`, error);
        }
    }
    closePty(socket, data) {
        try {
            const { sessionId } = data;
            const session = this.sessions.get(sessionId);
            if (!session) {
                this.logger.warn(`尝试关闭不存在的会话: ${sessionId}`);
                return;
            }
            this.logger.info(`关闭PTY会话: ${sessionId}`);
            if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                this.logger.info(`终止输出流转发进程: ${sessionId}`);
                if (session.streamForwardProcess.stdin && !session.streamForwardProcess.stdin.destroyed) {
                    session.streamForwardProcess.stdin.end();
                }
                this.forceKillProcess(session.streamForwardProcess, '输出流转发进程', () => {
                    session.streamForwardProcess = undefined;
                });
            }
            if (!session.process.killed) {
                if (session.process.stdin && !session.process.stdin.destroyed) {
                    session.process.stdin.end();
                }
                session.process.kill('SIGTERM');
                setTimeout(() => {
                    if (!session.process.killed) {
                        this.logger.warn(`强制终止PTY进程: ${sessionId}`);
                        session.process.kill('SIGKILL');
                    }
                }, 3000);
            }
            this.sessions.delete(sessionId);
            this.sessionManager.removeSession(sessionId).catch(error => {
                this.logger.error(`从配置文件删除会话失败: ${sessionId}`, error);
            });
            socket.emit('pty-closed', { sessionId });
        }
        catch (error) {
            this.logger.error(`关闭PTY会话失败:`, error);
        }
    }
    handleDisconnect(socket) {
        try {
            const sessionsToMark = [];
            for (const [sessionId, session] of this.sessions.entries()) {
                if (session.socket.id === socket.id) {
                    sessionsToMark.push(sessionId);
                }
            }
            for (const sessionId of sessionsToMark) {
                const session = this.sessions.get(sessionId);
                if (session) {
                    session.disconnected = true;
                    session.disconnectedAt = new Date();
                    session.lastActivity = new Date();
                    this.sessionManager.setSessionActive(sessionId, false).catch(error => {
                        this.logger.error(`更新会话断开状态失败: ${sessionId}`, error);
                    });
                    this.logger.info(`会话 ${sessionId} 已标记为断开状态`);
                }
            }
            if (sessionsToMark.length > 0) {
                this.logger.info(`客户端断开连接，标记了 ${sessionsToMark.length} 个会话为断开状态`);
            }
        }
        catch (error) {
            this.logger.error(`处理客户端断开连接失败:`, error);
        }
    }
    cleanupInactiveSessions() {
        try {
            const now = new Date();
            const inactiveThreshold = 30 * 60 * 1000;
            const disconnectedThreshold = 5 * 60 * 1000;
            const sessionsToClose = [];
            for (const [sessionId, session] of this.sessions.entries()) {
                const inactiveTime = now.getTime() - session.lastActivity.getTime();
                const disconnectedTime = session.disconnectedAt ? now.getTime() - session.disconnectedAt.getTime() : 0;
                if ((session.disconnected && disconnectedTime > disconnectedThreshold) ||
                    (!session.disconnected && inactiveTime > inactiveThreshold)) {
                    sessionsToClose.push(sessionId);
                }
            }
            for (const sessionId of sessionsToClose) {
                const session = this.sessions.get(sessionId);
                if (session) {
                    this.logger.info(`清理会话: ${sessionId} (${session.disconnected ? '断开连接' : '不活跃'})`);
                    this.closePty(session.socket, { sessionId });
                }
            }
        }
        catch (error) {
            this.logger.error(`清理不活跃会话失败:`, error);
        }
    }
    reconnectSession(socket, sessionId) {
        try {
            const session = this.sessions.get(sessionId);
            if (!session) {
                this.logger.warn(`尝试重连不存在的会话: ${sessionId}`);
                return false;
            }
            session.socket = socket;
            session.disconnected = false;
            session.disconnectedAt = undefined;
            session.lastActivity = new Date();
            this.sessionManager.setSessionActive(sessionId, true).catch(error => {
                this.logger.error(`更新会话重连状态失败: ${sessionId}`, error);
            });
            this.logger.info(`会话 ${sessionId} 重新连接成功`);
            session.process.stdout?.removeAllListeners('data');
            session.process.stderr?.removeAllListeners('data');
            if (session.outputBuffer.length > 0) {
                const historicalOutput = session.outputBuffer.join('');
                socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: historicalOutput,
                    isHistorical: true
                });
            }
            session.process.stdout?.on('data', (data) => {
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: output
                });
            });
            session.process.stderr?.on('data', (data) => {
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                socket.emit('terminal-output', {
                    sessionId: session.id,
                    data: output
                });
            });
            return true;
        }
        catch (error) {
            this.logger.error(`重连会话失败:`, error);
            return false;
        }
    }
    async updateSessionName(sessionId, newName) {
        try {
            const session = this.sessions.get(sessionId);
            if (!session) {
                this.logger.warn(`尝试更新不存在的会话名称: ${sessionId}`);
                return false;
            }
            session.name = newName;
            session.lastActivity = new Date();
            await this.sessionManager.updateSessionName(sessionId, newName);
            this.logger.info(`会话名称已更新: ${sessionId} -> ${newName}`);
            return true;
        }
        catch (error) {
            this.logger.error(`更新会话名称失败: ${sessionId}`, error);
            return false;
        }
    }
    getActiveSessions() {
        return Array.from(this.sessions.values()).map(session => ({
            id: session.id,
            name: session.name,
            workingDirectory: session.workingDirectory,
            createdAt: session.createdAt,
            lastActivity: session.lastActivity,
            hasStreamForward: session.enableStreamForward || false,
            streamForwardStatus: this.getStreamForwardStatus(session)
        }));
    }
    getStreamForwardStatus(session) {
        if (!session.enableStreamForward) {
            return '未启用';
        }
        if (!session.streamForwardProcess) {
            return '未运行';
        }
        if (session.streamForwardProcess.killed) {
            return '已终止';
        }
        return `运行中 (PID: ${session.streamForwardProcess.pid})`;
    }
    getSessionStatusInfo(session) {
        const now = new Date();
        const uptime = Math.floor((now.getTime() - session.createdAt.getTime()) / 1000);
        const lastActivity = Math.floor((now.getTime() - session.lastActivity.getTime()) / 1000);
        let statusInfo = `\r\n=== 会话状态信息 ===\r\n`;
        statusInfo += `会话ID: ${session.id}\r\n`;
        statusInfo += `会话名称: ${session.name}\r\n`;
        statusInfo += `工作目录: ${session.workingDirectory}\r\n`;
        statusInfo += `运行时间: ${uptime}秒\r\n`;
        statusInfo += `最后活动: ${lastActivity}秒前\r\n`;
        statusInfo += `PTY进程PID: ${session.process.pid}\r\n`;
        statusInfo += `PTY进程状态: ${session.process.killed ? '已终止' : '运行中'}\r\n`;
        if (session.enableStreamForward) {
            statusInfo += `输出流转发: 已启用\r\n`;
            statusInfo += `转发程序: ${session.programPath || '未设置'}\r\n`;
            statusInfo += `转发进程状态: ${this.getStreamForwardStatus(session)}\r\n`;
            statusInfo += `自动关闭: ${session.autoCloseOnForwardExit ? '是' : '否'}\r\n`;
        }
        else {
            statusInfo += `输出流转发: 未启用\r\n`;
        }
        statusInfo += `输出缓存: ${session.outputBuffer.length}条记录\r\n`;
        statusInfo += `连接状态: ${session.disconnected ? '已断开' : '已连接'}\r\n`;
        statusInfo += `===================\r\n`;
        return statusInfo;
    }
    getSessionStats() {
        const sessions = Array.from(this.sessions.values())
            .map(session => ({
            id: session.id,
            name: session.name,
            createdAt: session.createdAt,
            lastActivity: session.lastActivity,
            disconnected: session.disconnected
        }));
        return {
            total: sessions.length,
            sessions
        };
    }
    getSavedSessions() {
        return this.sessionManager.getSavedSessions();
    }
    async getActiveTerminalProcesses() {
        const activeProcesses = [];
        for (const [sessionId, session] of this.sessions.entries()) {
            if (!session.disconnected && session.process && !session.process.killed) {
                const pid = session.process.pid || 0;
                let cpu = 0;
                let memory = 0;
                if (pid > 0) {
                    try {
                        const processStats = await this.getProcessStats(pid);
                        cpu = processStats.cpu;
                        memory = processStats.memory;
                    }
                    catch (error) {
                        this.logger.warn(`获取进程 ${pid} 统计信息失败:`, error);
                    }
                }
                activeProcesses.push({
                    id: session.id,
                    name: session.name,
                    pid,
                    cpu,
                    memory,
                    status: 'running',
                    createdAt: session.createdAt.toISOString(),
                    command: 'terminal session'
                });
            }
        }
        return activeProcesses;
    }
    async getProcessStats(pid) {
        try {
            const platform = os.platform();
            if (platform === 'win32') {
                const { stdout } = await execAsync(`wmic process where "ProcessId=${pid}" get PageFileUsage,WorkingSetSize /format:csv`);
                const lines = stdout.trim().split('\n');
                if (lines.length > 1) {
                    const data = lines[1].split(',');
                    const memory = parseInt(data[1]) || 0;
                    return { cpu: 0, memory: memory / 1024 / 1024 };
                }
            }
            else {
                const { stdout } = await execAsync(`ps -p ${pid} -o %cpu,%mem --no-headers`);
                const parts = stdout.trim().split(/\s+/);
                if (parts.length >= 2) {
                    const cpu = parseFloat(parts[0]) || 0;
                    const memory = parseFloat(parts[1]) || 0;
                    return { cpu, memory };
                }
            }
        }
        catch (error) {
            this.logger.warn(`获取进程 ${pid} 统计信息失败:`, error);
        }
        return { cpu: 0, memory: 0 };
    }
    async checkCommandExists(command) {
        try {
            if (os.platform() === 'win32') {
                await execAsync(`where ${command}`);
                return true;
            }
            else {
                await execAsync(`which ${command}`);
                return true;
            }
        }
        catch (error) {
            this.logger.debug(`命令 '${command}' 不存在:`, error);
            return false;
        }
    }
    async checkUserExists(username) {
        try {
            if (os.platform() !== 'linux') {
                return false;
            }
            const { stdout } = await execAsync(`id -u ${username}`);
            return stdout.trim() !== '';
        }
        catch (error) {
            this.logger.debug(`检查用户 '${username}' 是否存在时出错:`, error);
            return false;
        }
    }
    async setDirectoryPermissions777(directoryPath) {
        try {
            if (os.platform() !== 'linux') {
                return;
            }
            try {
                await fsPromises.access(directoryPath, fs.constants.F_OK);
            }
            catch {
                this.logger.warn(`目录不存在，跳过权限设置: ${directoryPath}`);
                return;
            }
            const chmodCommand = `chmod -R 777 "${directoryPath}"`;
            await execAsync(chmodCommand);
            this.logger.info(`已递归设置目录权限为777: ${directoryPath}`);
        }
        catch (error) {
            this.logger.error(`设置目录权限失败: ${directoryPath}`, error);
            throw error;
        }
    }
    detectControlCharacter(input) {
        const controlChars = {
            '\x03': { name: 'Ctrl+C', code: '\\x03', signal: 'SIGINT' },
            '\x1a': { name: 'Ctrl+Z', code: '\\x1a', signal: 'SIGTSTP' },
            '\x1c': { name: 'Ctrl+\\', code: '\\x1c', signal: 'SIGQUIT' },
            '\x04': { name: 'Ctrl+D', code: '\\x04', signal: 'EOF' },
            '\x15': { name: 'Ctrl+U', code: '\\x15', signal: 'KILL_LINE' },
            '\x0c': { name: 'Ctrl+L', code: '\\x0c', signal: 'CLEAR' },
        };
        return controlChars[input] || null;
    }
    async createPtyFallback(sessionId, sessionName, workingDirectory, socket, enableStreamForward, programPath, autoCloseOnForwardExit) {
        try {
            this.logger.info(`使用当前用户创建PTY回退会话: ${sessionId}`);
            const args = [
                '-dir', workingDirectory,
                '-size', '100,30',
                '-coder', 'UTF-8'
            ];
            const terminalEnv = buildUtf8LocaleEnv({
                ...process.env,
                TERM: 'xterm-256color',
                COLORTERM: 'truecolor'
            });
            args.push('-cmd', JSON.stringify(['/bin/bash', '--login']));
            this.logger.info(`使用当前用户启动终端，工作目录: ${workingDirectory}`);
            this.logger.info(`启动PTY回退进程: ${this.ptyPath} ${args.join(' ')}`);
            const ptyProcess = spawn(this.ptyPath, args, {
                stdio: ['pipe', 'pipe', 'pipe'],
                cwd: workingDirectory,
                env: terminalEnv,
                detached: os.platform() !== 'win32'
            });
            this.logger.info(`PTY回退进程已启动，PID: ${ptyProcess.pid}`);
            const session = {
                id: sessionId,
                name: sessionName,
                process: ptyProcess,
                socket,
                workingDirectory,
                createdAt: new Date(),
                lastActivity: new Date(),
                outputBuffer: [],
                enableStreamForward,
                programPath,
                autoCloseOnForwardExit,
                fallbackRetried: true
            };
            this.sessions.set(sessionId, session);
            ptyProcess.stdout?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                socket.emit('terminal-output', { sessionId, data: output });
            });
            ptyProcess.stderr?.on('data', (data) => {
                session.lastActivity = new Date();
                const output = data.toString();
                session.outputBuffer.push(output);
                if (session.outputBuffer.length > 1000) {
                    session.outputBuffer.shift();
                }
                socket.emit('terminal-output', { sessionId, data: output });
            });
            ptyProcess.on('exit', (code, signal) => {
                this.logger.info(`PTY回退进程退出: ${sessionId}, 退出码: ${code}, 信号: ${signal}`);
                socket.emit('terminal-exit', { sessionId, code: code || 0, signal });
                this.sessions.delete(sessionId);
            });
            ptyProcess.on('error', (error) => {
                this.logger.error(`PTY回退进程错误 ${sessionId}:`, error);
                socket.emit('terminal-error', { sessionId, error: error.message });
                this.sessions.delete(sessionId);
            });
            socket.emit('pty-created', { sessionId, workingDirectory });
            this.logger.info(`PTY回退会话创建成功: ${sessionId}`);
        }
        catch (error) {
            this.logger.error(`创建PTY回退会话失败:`, error);
            socket.emit('terminal-error', {
                sessionId,
                error: error instanceof Error ? error.message : '未知错误'
            });
        }
    }
    cleanup() {
        this.logger.info('开始清理所有终端会话...');
        for (const [sessionId, session] of this.sessions.entries()) {
            try {
                if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                    this.logger.info(`清理输出流转发进程: ${sessionId}`);
                    if (session.streamForwardProcess.stdin && !session.streamForwardProcess.stdin.destroyed) {
                        session.streamForwardProcess.stdin.end();
                    }
                    session.streamForwardProcess.kill('SIGTERM');
                    setTimeout(() => {
                        if (session.streamForwardProcess && !session.streamForwardProcess.killed) {
                            session.streamForwardProcess.kill('SIGKILL');
                        }
                    }, 1000);
                }
                if (!session.process.killed) {
                    if (session.process.stdin && !session.process.stdin.destroyed) {
                        session.process.stdin.end();
                    }
                    session.process.kill('SIGTERM');
                    setTimeout(() => {
                        if (!session.process.killed) {
                            session.process.kill('SIGKILL');
                        }
                    }, 1000);
                }
            }
            catch (error) {
                this.logger.error(`清理会话 ${sessionId} 失败:`, error);
            }
        }
        this.sessions.clear();
        this.logger.info('所有终端会话已清理完成');
    }
    setSocketIO(io) {
        this.io = io;
        this.startActiveProcessesMonitoring();
    }
    startActiveProcessesMonitoring() {
        if (this.activeProcessesInterval) {
            clearInterval(this.activeProcessesInterval);
        }
        this.activeProcessesInterval = setInterval(async () => {
            if (this.io) {
                const room = this.io.sockets.adapter.rooms.get('terminal-processes');
                if (room && room.size > 0) {
                    try {
                        const activeProcesses = await this.getActiveTerminalProcesses();
                        this.io.to('terminal-processes').emit('terminal-processes-update', {
                            success: true,
                            data: activeProcesses,
                            timestamp: new Date().toISOString()
                        });
                    }
                    catch (error) {
                        this.logger.error('推送终端活跃进程数据失败:', error);
                        this.io.to('terminal-processes').emit('terminal-processes-update', {
                            success: false,
                            error: error instanceof Error ? error.message : '获取活跃进程失败',
                            timestamp: new Date().toISOString()
                        });
                    }
                }
            }
        }, 5000);
        this.logger.info('终端活跃进程监控已启动');
    }
    stopActiveProcessesMonitoring() {
        if (this.activeProcessesInterval) {
            clearInterval(this.activeProcessesInterval);
            this.activeProcessesInterval = undefined;
            this.logger.info('终端活跃进程监控已停止');
        }
    }
    async sendActiveProcessesToClient(socket) {
        try {
            const activeProcesses = await this.getActiveTerminalProcesses();
            socket.emit('terminal-processes-update', {
                success: true,
                data: activeProcesses,
                timestamp: new Date().toISOString()
            });
        }
        catch (error) {
            this.logger.error('向客户端发送终端活跃进程数据失败:', error);
            socket.emit('terminal-processes-update', {
                success: false,
                error: error instanceof Error ? error.message : '获取活跃进程失败',
                timestamp: new Date().toISOString()
            });
        }
    }
    handleClientDisconnect() {
        try {
            if (this.io) {
                const room = this.io.sockets.adapter.rooms.get('terminal-processes');
                if (!room || room.size === 0) {
                    this.stopActiveProcessesMonitoring();
                }
            }
        }
        catch (error) {
            this.logger.error('处理客户端断开后的终端进程订阅检查失败:', error);
        }
    }
}
