/**
 * 会话管理 API 路由
 *
 * 提供 SDK Agent 会话的查询和恢复功能
 */
import { execSync } from 'node:child_process';
import { Router } from 'express';
import { adapterRegistry } from '../adapter/index.js';
import { validateToken } from '../middleware/auth.js';
import { isProcessRunning, findOrphanProcessByAgentId, findOrphanProcessByWorkspace } from '../services/process-detector.js';
import { findPersistedSessionByAgentId, loadPersistedSessions, removePersistedSession, } from '../services/terminal-persistence.js';
import { createLogger } from '../utils/logger.js';
import { sdkSessions } from './terminal.js';
const log = createLogger('sessions');
export const sessionsRouter = Router();
/**
 * 解析 active SDK 会话快照状态。
 * 主流程：优先使用 adapter 细粒度状态，其次使用 terminal 路由内存里的最近 runtimeStatus，最后兼容旧会话回退 running。
 */
export function resolveActiveSdkSessionSnapshotStatus(adapterStatus, currentRuntimeStatus, currentRuntimeActionType) {
    const normalizedAdapterStatus = String(adapterStatus || '').trim();
    if (normalizedAdapterStatus) {
        const normalizedRuntimeStatus = String(currentRuntimeStatus || '').trim();
        const normalizedActionType = String(currentRuntimeActionType || '').trim().toLowerCase();
        if (normalizedAdapterStatus.toLowerCase() === 'tool_using' &&
            normalizedRuntimeStatus.toLowerCase() === 'waiting_input' &&
            normalizedActionType === 'idle') {
            return normalizedRuntimeStatus;
        }
        return normalizedAdapterStatus;
    }
    const normalizedRuntimeStatus = String(currentRuntimeStatus || '').trim();
    return normalizedRuntimeStatus || 'running';
}
/**
 * 获取所有 SDK Agent 会话
 * GET /runtime/sessions
 */
sessionsRouter.get('/sessions', validateToken, async (_req, res) => {
    try {
        // 1. 获取 SDK 会话
        const activeSdkSessions = Array.from(sdkSessions.entries()).map(([sessionId, entry]) => {
            const adapter = adapterRegistry.get(entry.providerId || 'claude-code');
            const status = resolveActiveSdkSessionSnapshotStatus(adapter.getSessionStatus(sessionId), entry.currentRuntimeStatus, entry.currentRuntimeActionType);
            return {
                sessionId,
                agentId: entry.agentId,
                workspacePath: entry.workspacePath,
                status,
                runtimeStatus: status,
                runtimeActionType: entry.currentRuntimeActionType,
                runtimeActionLabel: entry.currentRuntimeActionLabel,
                runtimeActionDetail: entry.currentRuntimeActionDetail,
                mode: 'sdk',
                startedAt: null,
            };
        });
        // 2. SDK-only：活跃会话全部来自 SDK adapter。
        const activeSessions = activeSdkSessions;
        const persistedSessions = await loadPersistedSessions();
        const activeSessionIds = new Set(activeSessions.map(s => s.sessionId));
        const persistedOnly = persistedSessions.filter(s => !activeSessionIds.has(s.sessionId));
        const response = {
            ok: true,
            active: activeSessions,
            persisted: persistedOnly,
        };
        res.json(response);
    }
    catch (error) {
        const err = error;
        res.status(500).json({ error: err.message });
    }
});
/**
 * 恢复终端会话
 * POST /runtime/sessions/recover
 *
 * �?支持孤儿进程检测：
 * 如果持久化会话中�?PID 且进程仍在运行，标记�?orphan_recovered
 */
sessionsRouter.post('/sessions/recover', validateToken, async (req, res) => {
    const { agentId, workspacePath, command } = req.body;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 检查是否有 SDK 活跃会话
        const existingSdkSession = Array.from(sdkSessions.entries()).find(([, s]) => s.agentId === agentId);
        if (existingSdkSession) {
            const adapter = adapterRegistry.get(existingSdkSession[1].providerId || 'claude-code');
            const status = resolveActiveSdkSessionSnapshotStatus(adapter.getSessionStatus(existingSdkSession[0]), existingSdkSession[1].currentRuntimeStatus, existingSdkSession[1].currentRuntimeActionType);
            res.json({
                ok: true,
                sessionId: existingSdkSession[0],
                agentId,
                workspacePath: existingSdkSession[1].workspacePath,
                command: existingSdkSession[1].config.command,
                status,
                runtimeStatus: status,
                runtimeActionType: existingSdkSession[1].currentRuntimeActionType,
                runtimeActionLabel: existingSdkSession[1].currentRuntimeActionLabel,
                runtimeActionDetail: existingSdkSession[1].currentRuntimeActionDetail,
                mode: 'sdk',
                recovered: false,
                message: 'SDK session already active',
            });
            return;
        }
        // 3. 获取持久化会话信�?
        const persistedSession = await findPersistedSessionByAgentId(agentId);
        // �?4. 检查孤儿进程（如果持久化会话中�?PID�?
        let orphanDetected = false;
        let orphanPid;
        if (persistedSession?.pid && isProcessRunning(persistedSession.pid)) {
            orphanDetected = true;
            orphanPid = persistedSession.pid;
            log.info(`[Recover] Detected orphan process for agentId=${agentId}, pid=${persistedSession.pid}`);
        }
        else if (persistedSession?.mode === 'sdk' || !persistedSession?.pid) {
            // SDK 模式或无 PID，尝试通过 agentId 查找孤儿进程
            const orphanProcess = findOrphanProcessByAgentId(agentId);
            if (orphanProcess) {
                orphanDetected = true;
                orphanPid = orphanProcess.pid;
                log.info(`[Recover] Found orphan process by agentId search: agentId=${agentId}, pid=${orphanProcess.pid}`);
            }
        }
        const resolvedWorkspacePath = workspacePath || persistedSession?.workspacePath;
        const resolvedCommand = command || persistedSession?.command || 'acode';
        const resolvedMode = persistedSession?.mode || 'sdk';
        if (!resolvedWorkspacePath) {
            res.status(400).json({ error: 'workspacePath is required (not found in persisted session)' });
            return;
        }
        // �?5. 如果检测到孤儿进程，返回孤儿进程信息（不启动新进程�?
        // �?aws-mcp-server 决定如何处理（可能需要清理或重新连接�?
        if (orphanDetected && orphanPid) {
            log.info(`[Recover] Returning orphan process info for agentId=${agentId}`);
            res.json({
                ok: true,
                sessionId: persistedSession?.sessionId || '',
                agentId,
                workspacePath: resolvedWorkspacePath,
                command: resolvedCommand,
                status: 'orphan_detected',
                runtimeStatus: persistedSession?.runtimeStatus,
                runtimeActionType: persistedSession?.runtimeActionType,
                runtimeActionLabel: persistedSession?.runtimeActionLabel,
                runtimeActionDetail: persistedSession?.runtimeActionDetail,
                recovered: false,
                orphan: {
                    pid: orphanPid,
                    message: 'Found orphan process still running. Manual intervention may be required.',
                },
                mode: resolvedMode,
            });
            return;
        }
        // 6. SDK-only 恢复不再创建本地终端；由上游重新调用 /runtime/start 创建新的 SDK 会话。
        await removePersistedSession(persistedSession?.sessionId || '');
        const result = {
            ok: false,
            sessionId: persistedSession?.sessionId || '',
            agentId,
            workspacePath: resolvedWorkspacePath,
            command: resolvedCommand,
            status: 'stopped',
            recovered: false,
            message: 'No active SDK session found; start a new SDK runtime session instead.',
        };
        res.json(result);
    }
    catch (error) {
        const err = error;
        log.error('Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 搜索残留进程（孤儿进程）
 * POST /runtime/search-orphan
 *
 * 根据 agentId 搜索标记了该 agentId 的残留进程（不在 runtime-bridge 管理范围内的进程�?
 * 用于：当 agent.isOnline �?true �?runtime-bridge 没有管理它的会话时，手动搜索残留进程
 *
 * 改进策略�?
 * 1. 检�?runtime-bridge 是否有活跃会�?
 * 2. 通过进程命令�?环境变量搜索（findOrphanProcessByAgentId�?
 * 3. 检查持久化会话中的 PID 是否存活（新增：即使进程列表匹配不到，PID 存活也报告）
 */
sessionsRouter.post('/search-orphan', validateToken, async (req, res) => {
    const { agentId, workspacePath } = req.body;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 首先检查 runtime-bridge 是否已经有活跃 SDK 会话
        const activeSdkSession = Array.from(sdkSessions.entries()).find(([, s]) => s.agentId === agentId);
        const hasActiveSession = activeSdkSession;
        // 2. 搜索标记了该 agentId 的进程（命令�?+ 环境变量 + 进程树匹配）
        const orphanProcess = findOrphanProcessByAgentId(agentId);
        // 3. 如果找到残留进程，返回进程信�?
        if (orphanProcess) {
            log.info(`[search-orphan] Found orphan process for agentId=${agentId}, pid=${orphanProcess.pid}`);
            res.json({
                ok: true,
                agentId,
                hasActiveSession,
                found: true,
                orphan: {
                    pid: orphanProcess.pid,
                    command: orphanProcess.command,
                    cwd: orphanProcess.cwd,
                    startedAt: orphanProcess.startedAt,
                    message: 'Found orphan process. Click terminate to stop it.',
                },
            });
            return;
        }
        // 4. 检查持久化会话中的 PID 是否仍然存活
        // 即使进程列表匹配不到（命令行特征未识别），PID 存活说明进程仍在运行
        const persistedSession = await findPersistedSessionByAgentId(agentId);
        if (persistedSession?.pid && isProcessRunning(persistedSession.pid)) {
            log.info(`[search-orphan] Found orphan by persisted PID: agentId=${agentId}, pid=${persistedSession.pid}`);
            res.json({
                ok: true,
                agentId,
                hasActiveSession,
                found: true,
                orphan: {
                    pid: persistedSession.pid,
                    command: persistedSession.command || '(persisted session)',
                    message: 'Found orphan process by persisted PID. Click terminate to stop it.',
                },
            });
            return;
        }
        // �?5. 通过工作目录宽泛搜索（当 agentId 和持久化 PID 都匹配不到时�?
        // 前端传递的 workspacePath，或者从持久化会话中获取
        const searchWorkspace = workspacePath || persistedSession?.workspacePath;
        if (searchWorkspace) {
            const workspaceOrphan = findOrphanProcessByWorkspace(searchWorkspace);
            if (workspaceOrphan) {
                log.info(`[search-orphan] Found orphan by workspace: agentId=${agentId}, pid=${workspaceOrphan.pid}, workspace=${searchWorkspace}`);
                res.json({
                    ok: true,
                    agentId,
                    hasActiveSession,
                    found: true,
                    orphan: {
                        pid: workspaceOrphan.pid,
                        command: workspaceOrphan.command,
                        message: 'Found orphan process by workspace path. Click terminate to stop it.',
                    },
                });
                return;
            }
        }
        // 6. 没找到残留进�?
        log.info(`[search-orphan] No orphan process found for agentId=${agentId}, hasActiveSession=${!!hasActiveSession}`);
        res.json({
            ok: true,
            agentId,
            hasActiveSession: !!hasActiveSession,
            found: false,
            orphan: null,
            message: hasActiveSession
                ? 'Agent has active session in runtime-bridge'
                : 'No orphan process and no active session found',
        });
    }
    catch (error) {
        const err = error;
        log.error('[search-orphan] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 终止残留进程
 * POST /runtime/terminate-orphan
 *
 * 终止�?search-orphan 找到的残留进�?
 */
sessionsRouter.post('/terminate-orphan', validateToken, async (req, res) => {
    const { agentId, pid } = req.body;
    if (!agentId || !pid) {
        res.status(400).json({ error: 'agentId and pid are required' });
        return;
    }
    try {
        // 1. 检查进程是否还在运�?
        if (!isProcessRunning(pid)) {
            res.json({
                ok: true,
                agentId,
                pid,
                terminated: false,
                message: 'Process already terminated',
            });
            return;
        }
        // 2. 终止进程（在 Windows 上使�?taskkill，Unix 上使�?kill�?
        const platform = process.platform;
        let success = false;
        if (platform === 'win32') {
            try {
                execSync(`taskkill /PID ${pid} /T /F`, { encoding: 'utf8', timeout: 5000 });
                success = true;
            }
            catch (e) {
                log.warn(`[terminate-orphan] taskkill failed for pid=${pid}:`, e);
            }
        }
        else {
            try {
                process.kill(pid, 'SIGTERM');
                success = true;
            }
            catch (e) {
                log.warn(`[terminate-orphan] kill failed for pid=${pid}:`, e);
            }
        }
        if (success) {
            log.info(`[terminate-orphan] Terminated orphan process for agentId=${agentId}, pid=${pid}`);
            res.json({
                ok: true,
                agentId,
                pid,
                terminated: true,
                message: 'Orphan process terminated successfully',
            });
        }
        else {
            res.json({
                ok: true,
                agentId,
                pid,
                terminated: false,
                message: 'Failed to terminate process',
            });
        }
    }
    catch (error) {
        const err = error;
        log.error('[terminate-orphan] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 根据 agentId 获取会话状�?
 * GET /runtime/sessions/by-agent/:agentId
 *
 * 增强返回：包含进程健康状态、是否是孤儿进程等信�?
 */
sessionsRouter.get('/sessions/by-agent/:agentId', validateToken, async (req, res) => {
    const agentIdParam = req.params.agentId;
    const agentId = Array.isArray(agentIdParam) ? agentIdParam[0] : agentIdParam;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 检查活跃 SDK 会话
        const activeSdkSession = Array.from(sdkSessions.entries()).find(([, s]) => s.agentId === agentId);
        if (activeSdkSession) {
            const adapter = adapterRegistry.get(activeSdkSession[1].providerId || 'claude-code');
            const pid = adapter.getSessionPid?.(activeSdkSession[0]);
            const status = resolveActiveSdkSessionSnapshotStatus(adapter.getSessionStatus(activeSdkSession[0]), activeSdkSession[1].currentRuntimeStatus, activeSdkSession[1].currentRuntimeActionType);
            res.json({
                ok: true,
                sessionId: activeSdkSession[0],
                agentId,
                workspacePath: activeSdkSession[1].workspacePath,
                status,
                runtimeStatus: status,
                isActive: true,
                mode: 'sdk',
                pid,
                isManaged: true,
                providerId: activeSdkSession[1].providerId,
            });
            return;
        }
        // 2. 检查持久化会话
        const persistedSession = await findPersistedSessionByAgentId(agentId);
        if (persistedSession) {
            // 检查进程是否仍在运�?
            const { isProcessRunning } = await import('../services/process-detector.js');
            const isProcessAlive = persistedSession.pid ? isProcessRunning(persistedSession.pid) : false;
            res.json({
                ok: true,
                sessionId: persistedSession.sessionId,
                agentId,
                workspacePath: persistedSession.workspacePath,
                command: persistedSession.command,
                status: isProcessAlive ? 'orphan' : 'stopped',
                runtimeStatus: persistedSession.runtimeStatus,
                runtimeActionType: persistedSession.runtimeActionType,
                runtimeActionLabel: persistedSession.runtimeActionLabel,
                runtimeActionDetail: persistedSession.runtimeActionDetail,
                startedAt: persistedSession.startedAt,
                isActive: false,
                mode: persistedSession.mode,
                pid: persistedSession.pid,
                isManaged: false,
                isProcessAlive,
                isOrphan: isProcessAlive, // 进程在运行但 bridge 未管�?
            });
            return;
        }
        res.json({
            ok: true,
            agentId,
            status: 'none',
            isActive: false,
            isManaged: false,
        });
    }
    catch (error) {
        const err = error;
        log.error('[sessions/by-agent] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 接管已存在的SDK会话
 * POST /runtime/takeover-session
 *
 * 当aws-mcp-server重启后，用于重新获取bridge中已存在的SDK会话控制�?
 * 不会启动新进程，只是重新建立会话关联
 */
sessionsRouter.post('/takeover-session', validateToken, async (req, res) => {
    const { agentId } = req.body;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 检查是否已有活跃 SDK 会话
        const existingSdkSession = Array.from(sdkSessions.entries()).find(([, s]) => s.agentId === agentId);
        if (existingSdkSession) {
            res.json({
                ok: true,
                agentId,
                sessionId: existingSdkSession[0],
                mode: 'sdk',
                status: 'running',
                isActive: true,
                recovered: false,
                message: 'SDK session already active',
            });
            return;
        }
        // 2. 查找持久化会�?
        const persistedSession = await findPersistedSessionByAgentId(agentId);
        if (!persistedSession) {
            res.status(404).json({
                error: 'No persisted session found for this agentId',
                agentId,
            });
            return;
        }
        // 3. 检查 SDK 进程是否仍在运行
        let isProcessAlive = false;
        if (persistedSession.mode === 'sdk') {
            // 对于SDK模式，尝试通过agentId查找进程
            const orphanProcess = findOrphanProcessByAgentId(agentId);
            isProcessAlive = !!orphanProcess;
            if (!isProcessAlive && persistedSession.pid) {
                // 如果通过agentId没找到，尝试通过PID检�?
                isProcessAlive = isProcessRunning(persistedSession.pid);
            }
        }
        if (!isProcessAlive) {
            log.info(`[takeover-session] Process not alive for agentId=${agentId}, mode=${persistedSession.mode}`);
            res.json({
                ok: false,
                agentId,
                status: 'process_not_alive',
                isActive: false,
                message: 'Agent process is no longer running',
            });
            return;
        }
        // 5. 进程仍在运行，恢复会话控�?
        log.info(`[takeover-session] Taking over session for agentId=${agentId}, mode=${persistedSession.mode}, pid=${persistedSession.pid}`);
        // 如果是SDK模式，检查是否已经有活跃的SDK会话（bridge重启后可能丢失）
        if (persistedSession.mode === 'sdk') {
            // 尝试通过进程检测找到实际的SDK进程
            const orphanProcess = findOrphanProcessByAgentId(agentId);
            if (orphanProcess) {
                log.info(`[takeover-session] Found SDK process for agentId=${agentId}, pid=${orphanProcess.pid}`);
                // �?重要：SDK模式下，进程仍在运行，但bridge的内存中可能没有sdkSessions记录
                // 我们需要告诉aws-mcp-server这个session可以被接�?
                // aws-mcp-server会通过WebSocket重新连接到这个SDK进程
                res.json({
                    ok: true,
                    agentId,
                    sessionId: persistedSession.sessionId,
                    mode: 'sdk',
                    status: 'running',
                    isActive: true,
                    recovered: true,
                    pid: orphanProcess.pid || persistedSession.pid,
                    message: 'SDK session process found, can be taken over by aws-mcp-server',
                });
            }
            else {
                // 进程不在运行
                res.json({
                    ok: false,
                    agentId,
                    status: 'process_not_alive',
                    isActive: false,
                    message: 'SDK process not found',
                });
            }
        }
        else {
            res.status(410).json({
                error: 'Session takeover is no longer supported; start a new SDK runtime session.',
                agentId,
                mode: 'sdk',
            });
        }
    }
    catch (error) {
        const err = error;
        log.error('[takeover-session] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 强制终止 Agent 进程树（包括所有子进程�?
 * POST /runtime/terminate-tree
 *
 * 用于：当 Agent 脱离控制时，强制终止整个进程�?
 */
sessionsRouter.post('/terminate-tree', validateToken, async (req, res) => {
    const { agentId, sessionId } = req.body;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 查找会话（优先使�?sessionId，否则通过 agentId 查找�?
        let targetSessionId = sessionId;
        if (!targetSessionId) {
            const persistedSession = await findPersistedSessionByAgentId(agentId);
            if (!persistedSession) {
                res.status(404).json({ error: 'Session not found for this agentId' });
                return;
            }
            targetSessionId = persistedSession.sessionId;
        }
        // 2. 检查是否是活跃会话
        const activeSdkSession = sdkSessions.get(targetSessionId);
        let pid;
        let mode;
        if (activeSdkSession) {
            const adapter = adapterRegistry.get(activeSdkSession.providerId || 'claude-code');
            pid = adapter.getSessionPid?.(targetSessionId);
            mode = 'sdk';
        }
        else {
            // 非活跃会话，从持久化中获取 PID
            const persistedSession = await findPersistedSessionByAgentId(agentId);
            if (!persistedSession?.pid) {
                res.status(404).json({ error: 'Session PID not found' });
                return;
            }
            pid = persistedSession.pid;
            mode = persistedSession.mode || 'sdk';
        }
        // 3. 终止进程树
        const { terminateProcessTree, waitForProcessExit } = await import('../services/process-detector.js');
        // pid 此时一定存在（前面已经检查过）
        if (!pid) {
            res.status(404).json({ error: 'PID not found' });
            return;
        }
        const result = terminateProcessTree(pid);
        // 4. 等待进程完全终止（最多 5 秒）
        const exited = await waitForProcessExit(pid, 5000);
        // 5. 清理持久化状�?
        await import('../services/terminal-persistence.js').then(m => m.removePersistedSession(targetSessionId));
        log.info(`[terminate-tree] Terminated process tree for agentId=${agentId}, pid=${pid}, mode=${mode}, terminated=${result.terminated}, failed=${result.failed}, exited=${exited}`);
        res.json({
            ok: true,
            agentId,
            pid,
            mode,
            terminated: result.terminated,
            failed: result.failed,
            exited,
            message: exited
                ? `Successfully terminated ${result.terminated} processes`
                : `Terminated ${result.terminated} processes, but process ${pid} still running`,
        });
    }
    catch (error) {
        const err = error;
        log.error('[terminate-tree] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
/**
 * 获取 Agent 健康状态
 * GET /runtime/health/:agentId
 *
 * 返回：
 * - 进程是否存活
 * - CPU/内存使用率
 * - 是否是孤儿进程（bridge 未管理）
 * - 会话详细信息
 */
sessionsRouter.get('/health/:agentId', validateToken, async (req, res) => {
    const agentIdParam = req.params.agentId;
    const agentId = Array.isArray(agentIdParam) ? agentIdParam[0] : agentIdParam;
    if (!agentId) {
        res.status(400).json({ error: 'agentId is required' });
        return;
    }
    try {
        // 1. 查找会话
        const persistedSession = await findPersistedSessionByAgentId(agentId);
        if (!persistedSession) {
            res.status(404).json({ error: 'Session not found' });
            return;
        }
        // 2. 检查是否是活跃会话
        const activeSdkSession = sdkSessions.get(persistedSession.sessionId);
        const isManaged = !!activeSdkSession;
        // 3. 获取健康状态
        const { checkProcessHealth } = await import('../services/process-detector.js');
        const healthResponse = {
            sessionId: persistedSession.sessionId,
            mode: persistedSession.mode,
            workspacePath: persistedSession.workspacePath,
            isManaged,
            isActive: !!activeSdkSession,
        };
        if (persistedSession.pid) {
            const health = await checkProcessHealth(persistedSession.pid, agentId);
            Object.assign(healthResponse, health);
        }
        else {
            Object.assign(healthResponse, {
                pid: 0,
                alive: false,
                cpu: 0,
                memoryMB: 0,
                status: 'dead',
                lastUpdate: new Date(),
            });
        }
        res.json({
            agentId,
            ...healthResponse,
        });
    }
    catch (error) {
        const err = error;
        log.error('[health] Error:', err);
        res.status(500).json({ error: err.message });
    }
});
