/**
 * @fileoverview Supervisor 进程管理器
 * @description 负责管理 Xvfb 环境和子服务的生命周期
 *
 * 功能:
 * - Linux 环境下启动 xvfb-run
 * - 使用 child_process.spawn 启动 server.js
 * - 监听 IPC 通道接收重启指令
 * - 子进程崩溃时自动重启
 */

import { spawn, spawnSync } from 'child_process';
import net from 'net';
import os from 'os';
import path from 'path';
import fs from 'fs';

// ==================== 配置 ====================

const isWindows = os.platform() === 'win32';

// IPC 通道路径
const IPC_PATH = isWindows
    ? '\\\\.\\pipe\\webai2api-supervisor'
    : path.join(os.tmpdir(), 'webai2api-supervisor.sock');

// 重启延迟(毫秒)
const RESTART_DELAY = 1000;

// 下次重启使用的参数(由 IPC 设置)
let restartArgs = null;

// ==================== 工具函数 ====================

/**
 * 简单日志
 * @param {string} level 
 * @param {string} message 
 */
function log(level, message) {
    const now = new Date();
    const pad = (n, len = 2) => String(n).padStart(len, '0');
    const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
    const time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
    const levelTag = level === 'ERROR' ? 'ERRO' : level;
    console.log(`${date} ${time} [${levelTag}] [看门狗] ${message}`);
}

/**
 * 检查命令是否存在(Linux)
 * @param {string} cmd 
 * @returns {boolean}
 */
function checkCommand(cmd) {
    if (isWindows) return true;
    const result = spawnSync('which', [cmd], { encoding: 'utf8' });
    return result.status === 0;
}

/**
 * 检查端口是否可用
 * @param {number} port 
 * @returns {Promise<boolean>}
 */
function isPortAvailable(port) {
    return new Promise((resolve) => {
        const server = net.createServer();
        server.once('error', () => resolve(false));
        server.once('listening', () => {
            server.close();
            resolve(true);
        });
        server.listen(port, '127.0.0.1');
    });
}

/**
 * 查找可用端口
 * @param {number} startPort - 起始端口
 * @param {number} maxTries - 最大尝试次数
 * @returns {Promise<number|null>}
 */
async function findAvailablePort(startPort, maxTries = 10) {
    for (let i = 0; i < maxTries; i++) {
        const port = startPort + i;
        if (await isPortAvailable(port)) {
            return port;
        }
    }
    return null;
}

/**
 * 检查 Xvfb 显示号是否可用
 * @param {number} displayNum 
 * @returns {boolean}
 */
function isDisplayAvailable(displayNum) {
    const lockFile = `/tmp/.X${displayNum}-lock`;
    const socketFile = `/tmp/.X11-unix/X${displayNum}`;
    return !fs.existsSync(lockFile) && !fs.existsSync(socketFile);
}

/**
 * 查找可用的显示号
 * @param {number} startNum - 起始显示号
 * @param {number} maxTries - 最大尝试次数
 * @returns {number}
 */
function findAvailableDisplay(startNum = 50, maxTries = 50) {
    for (let i = 0; i < maxTries; i++) {
        const num = startNum + i;
        if (isDisplayAvailable(num)) {
            return num;
        }
    }
    // 回退:使用随机显示号
    return 50 + Math.floor(Math.random() * 50);
}

// ==================== IPC 服务器 ====================

let serverProcess = null;
let isRestarting = false;

// VNC 状态追踪
let vncInfo = {
    enabled: false,
    port: 5900,
    display: ':99',
    xvfbMode: false
};

/**
 * 启动 IPC 服务器
 */
function startIpcServer() {
    // 清理旧的 socket 文件(Linux)
    if (!isWindows && fs.existsSync(IPC_PATH)) {
        try {
            fs.unlinkSync(IPC_PATH);
        } catch { }
    }

    const ipcServer = net.createServer((socket) => {
        socket.on('data', (data) => {
            const command = data.toString().trim();

            if (command === 'RESTART' || command.startsWith('RESTART:')) {
                // 支持 RESTART:参数 格式
                const extraArgs = command.includes(':') ? command.split(':')[1].split(' ').filter(Boolean) : [];
                log('INFO', `收到 IPC 指令: RESTART${extraArgs.length ? ' (参数: ' + extraArgs.join(' ') + ')' : ''}`);
                socket.write('OK\n');
                socket.end();
                restartServer(extraArgs);
            } else if (command === 'STOP') {
                log('INFO', '收到 IPC 指令: STOP');
                socket.write('OK\n');
                socket.end();
                stopAll();
            } else if (command === 'GET_VNC_INFO') {
                // 返回 VNC 状态信息并关闭连接
                socket.write(JSON.stringify(vncInfo) + '\n');
                socket.end();
            } else {
                socket.write('UNKNOWN_COMMAND\n');
                socket.end();
            }
        });
    });

    ipcServer.listen(IPC_PATH, () => {
        log('INFO', `IPC 服务器已启动: ${IPC_PATH}`);
    });

    ipcServer.on('error', (err) => {
        log('ERROR', `IPC 服务器错误: ${err.message}`);
    });

    return ipcServer;
}

// ==================== 子进程管理 ====================

// 不可恢复的退出码(不应自动重启)
const FATAL_EXIT_CODES = [
    78,  // 配置/依赖错误
];

/**
 * 启动 server.js 子进程
 * @param {string[]} [extraArgs] - 额外的命令行参数
 */
function startServer(extraArgs = []) {
    const serverPath = path.join(process.cwd(), 'src', 'server', 'server.js');

    // 检查 server.js 是否存在
    if (!fs.existsSync(serverPath)) {
        log('ERROR', `未找到 server.js: ${serverPath}`);
        process.exit(1);
    }

    const args = [serverPath, ...extraArgs];
    const env = {
        ...process.env,
        SUPERVISOR_IPC: IPC_PATH
    };

    log('INFO', '正在启动子服务 (src/server/server.js)...');

    serverProcess = spawn(process.execPath, args, {
        cwd: process.cwd(),
        env,
        stdio: 'inherit'  // 将子进程 stdio 直接输出到主控制台
    });

    serverProcess.on('exit', (code, signal) => {
        if (isRestarting) {
            log('INFO', '子服务已停止,准备重启...');
            isRestarting = false;
            // 如果有新参数,使用新参数;否则使用原参数
            const argsToUse = restartArgs !== null ? restartArgs : extraArgs;
            restartArgs = null; // 重置
            setTimeout(() => startServer(argsToUse), RESTART_DELAY);
        } else if (code !== 0 && code !== null) {
            // 检查是否为不可恢复的错误
            if (FATAL_EXIT_CODES.includes(code)) {
                log('ERROR', `子服务因配置/依赖错误退出 (code: ${code}),不会自动重启`);
                process.exit(code);
            }
            log('WARN', `子服务异常退出 (code: ${code}),将自动重启...`);
            setTimeout(() => startServer(extraArgs), RESTART_DELAY);
        } else {
            log('INFO', '子服务已正常退出');
            process.exit(0);
        }
    });

    serverProcess.on('error', (err) => {
        log('ERROR', `子服务启动失败: ${err.message}`);
        process.exit(1);
    });
}

/**
 * 重启子服务
 * @param {string[]} [newArgs] - 新的启动参数(将覆盖原有参数)
 */
function restartServer(newArgs = null) {
    if (isRestarting) {
        log('WARN', '重启已在进行中,忽略重复请求');
        return;
    }

    isRestarting = true;
    log('INFO', '正在重启子服务...');

    // 如果提供了新参数,更新启动参数
    if (newArgs !== null) {
        restartArgs = newArgs;
    }

    if (serverProcess) {
        serverProcess.kill('SIGTERM');
    }
}

/**
 * 停止所有服务
 */
function stopAll() {
    log('INFO', '正在停止所有服务...');

    if (serverProcess) {
        serverProcess.kill('SIGTERM');
    }

    setTimeout(() => process.exit(0), 500);
}

// ==================== Xvfb 处理(Linux) ====================

/**
 * 在 Xvfb 中启动
 * @param {string[]} originalArgs - 原始命令行参数
 */
function startInXvfb(originalArgs) {
    if (!checkCommand('xvfb-run')) {
        log('ERROR', '未找到 xvfb-run 命令');
        log('ERROR', '请先安装 Xvfb:');
        log('ERROR', ' - Ubuntu/Debian: sudo apt install xvfb');
        log('ERROR', ' - CentOS/RHEL:   sudo dnf install xorg-x11-server-Xvfb');
        process.exit(1);
    }

    // 查找可用的显示号(从 50 开始,避免与常用的冲突)
    const displayNum = findAvailableDisplay(50);
    log('INFO', `正在启动 Xvfb 虚拟显示器 (显示号: :${displayNum})...`);

    // 移除 -xvfb 参数
    const newArgs = originalArgs.filter(arg => arg !== '-xvfb');

    const xvfbArgs = [
        `--server-num=${displayNum}`,
        '--server-args=-ac -screen 0 1366x768x24',
        'env',
        'XVFB_RUNNING=true',
        `DISPLAY=:${displayNum}`,
        process.argv[0],
        process.argv[1],
        ...newArgs
    ];

    const xvfbProcess = spawn('xvfb-run', xvfbArgs, {
        stdio: 'inherit'
    });

    xvfbProcess.on('error', (err) => {
        log('ERROR', `Xvfb 启动失败: ${err.message}`);
        process.exit(1);
    });

    xvfbProcess.on('exit', (code) => {
        process.exit(code || 0);
    });

    // 处理退出信号
    process.on('SIGINT', () => xvfbProcess.kill('SIGTERM'));
    process.on('SIGTERM', () => xvfbProcess.kill('SIGTERM'));
}

/**
 * 启动 VNC 服务器
 * @param {string} display - 显示器编号
 */
async function startVncServer(display) {
    if (!checkCommand('x11vnc')) {
        log('WARN', '未找到 x11vnc 命令,跳过 VNC 启动');
        return;
    }

    // 查找可用的 VNC 端口(从 5900 开始)
    const vncPort = await findAvailablePort(5900, 100);
    if (!vncPort) {
        log('ERROR', '无法找到可用的 VNC 端口 (5900-5999)');
        return;
    }

    log('INFO', `正在启动 VNC 服务器 (端口: ${vncPort})...`);

    const vncProcess = spawn('x11vnc', [
        '-display', display,
        '-rfbport', String(vncPort),
        '-localhost',
        '-nopw',
        '-shared',
        '-forever',
        '-noxdamage',
        '-norc',
        '-geometry', '1366x768'
    ], {
        stdio: 'ignore',
        detached: false
    });

    vncProcess.on('error', (err) => {
        log('WARN', `VNC 启动失败: ${err.message}`);
        vncInfo.enabled = false;
    });

    vncProcess.on('exit', () => {
        vncInfo.enabled = false;
    });

    // 更新 VNC 状态
    vncInfo.enabled = true;
    vncInfo.port = vncPort;
    vncInfo.display = display;

    log('INFO', `VNC 服务器已启动,端口: ${vncPort}`);

    // 处理退出信号
    process.on('SIGINT', () => vncProcess.kill('SIGTERM'));
    process.on('SIGTERM', () => vncProcess.kill('SIGTERM'));
}

// ==================== 主入口 ====================

async function main() {
    const args = process.argv.slice(2);
    const hasXvfb = args.includes('-xvfb');
    const hasVnc = args.includes('-vnc');
    const isInXvfb = process.env.XVFB_RUNNING === 'true';
    const isLinux = os.platform() === 'linux';

    log('INFO', '主进程已启动');

    // 处理 Xvfb 参数(仅 Linux)
    if (hasXvfb && isLinux && !isInXvfb) {
        startInXvfb(args);
        return;
    }

    // 设置 xvfbMode 标识
    vncInfo.xvfbMode = isInXvfb;

    // 如果在 Xvfb 中运行,启动 VNC
    if (isInXvfb && hasVnc) {
        const display = process.env.DISPLAY || ':99';
        await startVncServer(display);
    }

    // 启动 IPC 服务器
    startIpcServer();

    // 启动子服务(过滤掉 -xvfb 和 -vnc 参数)
    const serverArgs = args.filter(arg => arg !== '-xvfb' && arg !== '-vnc');
    startServer(serverArgs);

    // 处理退出信号
    process.on('SIGINT', stopAll);
    process.on('SIGTERM', stopAll);
}

main().catch((err) => {
    log('ERROR', `启动失败: ${err.message}`);
    process.exit(1);
});