/**
 * 孤儿进程监控服务
 *
 * 定期扫描和检测孤儿进程，支持自动清理和告警
 */
import { createLogger } from '../utils/logger.js';
import { loadPersistedSessions, savePersistedSessions } from './terminal-persistence.js';
import { detectOrphanProcesses, checkAllSessionsHealth, terminateProcessTree, waitForProcessExit } from './process-detector.js';
import { ORPHAN_SCAN_INTERVAL, ORPHAN_AUTO_CLEAN_MODE, ORPHAN_SCAN_ENABLED, schedulerBaseUrl } from '../config.js';
import { getRuntimeAccessToken } from './runtime-binding.js';
import { shouldAutoCleanOrphanProcesses } from './runtime-lifecycle-policy.js';
const logger = createLogger('orphan-monitor');
/**
 * 孤儿进程监控器
 */
export class OrphanMonitor {
    constructor() {
        this.intervalId = null;
        this.lastScanTime = null;
        this.eventListeners = [];
        this.stopped = false; // ★ 停止标志位，用于中断正在执行的 scan()
    }
    /**
     * 启动监控器
     */
    async start() {
        if (!ORPHAN_SCAN_ENABLED) {
            logger.info('孤儿进程监控已禁用 (AWS_ORPHAN_SCAN_ENABLED=false)');
            return;
        }
        this.stopped = false; // ★ 重置停止标志
        logger.info(`启动孤儿进程监控，扫描间隔: ${ORPHAN_SCAN_INTERVAL}ms, 自动清理模式: ${ORPHAN_AUTO_CLEAN_MODE}`);
        // 立即执行一次检测
        await this.scan();
        // 设置定期扫描
        this.intervalId = setInterval(async () => {
            await this.scan();
        }, ORPHAN_SCAN_INTERVAL);
        logger.info('孤儿进程监控已启动');
    }
    /**
     * 停止监控器
     */
    stop() {
        this.stopped = true; // ★ 设置停止标志，中断正在执行的 scan()
        if (this.intervalId) {
            clearInterval(this.intervalId);
            this.intervalId = null;
            logger.info('孤儿进程监控已停止');
        }
    }
    /**
     * 执行一次扫描
     */
    async scan() {
        // ★ 如果已停止，立即退出
        if (this.stopped) {
            logger.debug('监控器已停止，跳过扫描');
            return;
        }
        this.lastScanTime = new Date();
        logger.debug('开始扫描孤儿进程...');
        try {
            // 加载持久化会话
            const persistedSessions = await loadPersistedSessions();
            // ★ 检查停止标志（异步操作后）
            if (this.stopped) {
                logger.debug('监控器已停止，中断扫描');
                return;
            }
            if (persistedSessions.length === 0) {
                logger.debug('无持久化会话，跳过扫描');
                return;
            }
            // 检测孤儿进程
            const orphans = detectOrphanProcesses(persistedSessions.map(s => ({
                agentId: s.agentId,
                pid: s.pid,
                workspacePath: s.workspacePath,
                command: s.command,
            })));
            // ★ 检查停止标志（异步操作后）
            if (this.stopped) {
                logger.debug('监控器已停止，中断扫描');
                return;
            }
            // 检测进程健康状态
            const healthStatuses = await checkAllSessionsHealth(persistedSessions.filter(s => s.pid).map(s => ({ agentId: s.agentId, pid: s.pid })));
            // ★ 检查停止标志（异步操作后）
            if (this.stopped) {
                logger.debug('监控器已停止，中断扫描');
                return;
            }
            // 处理孤儿进程
            for (const orphan of orphans) {
                if (this.stopped)
                    break; // ★ 循环中检查停止标志
                await this.handleOrphanDetected(orphan.agentId, orphan.process.pid);
            }
            // 处理健康异常进程
            for (const [agentId, health] of healthStatuses) {
                if (this.stopped)
                    break; // ★ 循环中检查停止标志
                if (health.status !== 'healthy' && health.alive) {
                    await this.handleHealthIssue(agentId, health);
                }
            }
            // 清理不存在的会话（PID 死了但记录还在）
            if (!this.stopped) {
                await this.cleanupDeadSessions(persistedSessions, healthStatuses);
            }
        }
        catch (error) {
            logger.warn('扫描孤儿进程失败:', error);
        }
    }
    /**
     * 处理检测到的孤儿进程
     */
    async handleOrphanDetected(agentId, pid) {
        const event = {
            type: 'orphan_detected',
            agentId,
            pid,
            message: `检测到孤儿进程: agentId=${agentId}, pid=${pid}`,
            timestamp: new Date(),
        };
        this.emit(event);
        logger.warn(`检测到孤儿进程: agentId=${agentId}, pid=${pid}`);
        // 根据模式处理。auto 模式也必须经过显式清理开关，避免重启恢复时误杀保留会话。
        switch (ORPHAN_AUTO_CLEAN_MODE) {
            case 'auto':
                if (shouldAutoCleanOrphanProcesses()) {
                    await this.autoCleanOrphan(agentId, pid);
                }
                else {
                    logger.warn('auto 模式未启用破坏性清理开关，改为告警并保留孤儿进程');
                    await this.reportToScheduler(agentId, 'orphan_detected', { pid });
                }
                break;
            case 'alert':
                // 告警并等待处理
                await this.reportToScheduler(agentId, 'orphan_detected', { pid });
                break;
            case 'manual':
                // 仅记录日志，等待手动处理
                logger.info('manual 模式，仅记录日志，不自动处理');
                break;
        }
    }
    /**
     * 处理健康异常
     */
    async handleHealthIssue(agentId, health) {
        const eventType = health.status === 'unresponsive' ? 'process_unresponsive'
            : health.status === 'high_cpu' ? 'process_high_cpu'
                : 'process_high_memory';
        const event = {
            type: eventType,
            agentId,
            pid: health.pid,
            message: `进程健康异常: ${health.status}, CPU=${health.cpu}%, Memory=${health.memoryMB}MB`,
            timestamp: new Date(),
            details: {
                cpu: health.cpu,
                memoryMB: health.memoryMB,
            },
        };
        this.emit(event);
        // 告警到调度中心
        await this.reportToScheduler(agentId, eventType, {
            pid: health.pid,
            cpu: health.cpu,
            memoryMB: health.memoryMB,
        });
        // auto 模式下也只有显式启用破坏性清理开关时才终止异常进程。
        if (ORPHAN_AUTO_CLEAN_MODE === 'auto'
            && health.status !== 'healthy'
            && shouldAutoCleanOrphanProcesses()) {
            logger.warn(`auto 模式: 终止异常进程 ${health.pid} (${health.status})`);
            await this.autoCleanOrphan(agentId, health.pid);
        }
        else if (ORPHAN_AUTO_CLEAN_MODE === 'auto' && health.status !== 'healthy') {
            logger.warn(`auto 模式未启用破坏性清理开关，保留异常进程 ${health.pid} (${health.status})`);
        }
    }
    /**
     * 自动清理孤儿进程
     */
    async autoCleanOrphan(agentId, pid) {
        logger.info(`自动清理孤儿进程：agentId=${agentId}, pid=${pid}`);
        // 使用进程树终止
        const result = terminateProcessTree(pid);
        // 等待进程完全终止（最多 5 秒）
        const exited = await waitForProcessExit(pid, 5000);
        if (result.terminated > 0 && exited) {
            const event = {
                type: 'orphan_cleaned',
                agentId,
                pid,
                message: `自动清理成功：agentId=${agentId}, pid=${pid}, 终止了 ${result.terminated} 个进程`,
                timestamp: new Date(),
                details: { terminated: result.terminated, failed: result.failed },
            };
            this.emit(event);
            await this.reportToScheduler(agentId, 'orphan_cleaned', { pid, terminated: result.terminated, failed: result.failed });
        }
        else {
            logger.warn(`自动清理失败：agentId=${agentId}, pid=${pid}, terminated=${result.terminated}, exited=${exited}`);
            await this.reportToScheduler(agentId, 'orphan_clean_failed', { pid, terminated: result.terminated, failed: result.failed });
        }
    }
    /**
     * 清理已死亡的会话记录
     */
    async cleanupDeadSessions(sessions, healthStatuses) {
        const deadSessions = sessions.filter(s => {
            if (!s.pid)
                return false;
            const health = healthStatuses.get(s.agentId);
            return !health?.alive;
        });
        if (deadSessions.length > 0) {
            logger.info(`清理 ${deadSessions.length} 个已死亡会话记录`);
            const aliveSessions = sessions.filter(s => {
                const health = healthStatuses.get(s.agentId);
                return health?.alive !== false;
            });
            await savePersistedSessions(aliveSessions);
        }
    }
    /**
     * 上报事件到调度中心
     */
    async reportToScheduler(agentId, eventType, details) {
        // ★ 如果已停止，跳过上报（关闭时调度中心可能已不可达）
        if (this.stopped) {
            logger.debug(`监控器已停止，跳过上报: ${eventType}`);
            return;
        }
        try {
            const runtimeAccessToken = getRuntimeAccessToken(undefined, schedulerBaseUrl) || getRuntimeAccessToken();
            if (!runtimeAccessToken) {
                logger.debug(`缺少 runtimeAccessToken，跳过上报: ${eventType}`);
                return;
            }
            const response = await fetch(`${schedulerBaseUrl}/api/runtime/orphan-event`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${runtimeAccessToken}`,
                },
                body: JSON.stringify({
                    agentId,
                    eventType,
                    details,
                    timestamp: new Date().toISOString(),
                }),
            });
            if (!response.ok) {
                // ★ 404 表示调度中心不可达或已关闭，降低日志级别避免噪音
                if (response.status === 404) {
                    logger.debug(`上报失败: 调度中心不可达 (404)，事件: ${eventType}`);
                }
                else {
                    logger.warn(`上报失败: ${response.status}`);
                }
            }
        }
        catch (error) {
            // ★ 网络错误时降低日志级别（关闭时常见）
            logger.debug('上报到调度中心失败:', error);
        }
    }
    /**
     * 注册事件监听器
     */
    onEvent(listener) {
        this.eventListeners.push(listener);
    }
    /**
     * 移除事件监听器
     */
    offEvent(listener) {
        const index = this.eventListeners.indexOf(listener);
        if (index > -1) {
            this.eventListeners.splice(index, 1);
        }
    }
    /**
     * 触发事件
     */
    emit(event) {
        for (const listener of this.eventListeners) {
            try {
                listener(event);
            }
            catch (error) {
                logger.warn('事件监听器执行失败:', error);
            }
        }
    }
    /**
     * 获取监控状态
     */
    getStatus() {
        return {
            running: this.intervalId !== null,
            lastScanTime: this.lastScanTime,
            mode: ORPHAN_AUTO_CLEAN_MODE,
        };
    }
}
// 单例实例
let orphanMonitorInstance = null;
/**
 * 获取孤儿进程监控器实例
 */
export function getOrphanMonitor() {
    if (!orphanMonitorInstance) {
        orphanMonitorInstance = new OrphanMonitor();
    }
    return orphanMonitorInstance;
}
/**
 * 启动孤儿进程监控
 */
export async function startOrphanMonitor() {
    const monitor = getOrphanMonitor();
    await monitor.start();
}
/**
 * 停止孤儿进程监控
 */
export function stopOrphanMonitor() {
    const monitor = getOrphanMonitor();
    monitor.stop();
}
