/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { spawn } from 'node:child_process';
import { randomBytes } from 'node:crypto';
const sessions = new Map();
const IDLE_TIMEOUT_MS = 900_000;
const REAP_INTERVAL_MS = 30_000;
let reaperInterval = null;
function startReaper() {
    if (reaperInterval)
        return;
    reaperInterval = setInterval(() => {
        const now = Date.now();
        for (const [id, session] of sessions) {
            if (session.process.exitCode !== null) {
                sessions.delete(id);
            }
            else if (now - session.lastActivity.getTime() > IDLE_TIMEOUT_MS) {
                kill(id);
            }
        }
    }, REAP_INTERVAL_MS);
    reaperInterval.unref();
}
export function generateSessionId() {
    return randomBytes(12).toString('hex');
}
export function spawnChat(sessionId, message, workspace, runtime = 'claude', context) {
    const existing = sessions.get(sessionId);
    if (existing) {
        if (existing.process.exitCode !== null) {
            return chainSession(sessionId, existing, message);
        }
        kill(sessionId);
    }
    const prompt = context ? `${context}\n\n${message}` : message;
    let proc;
    if (runtime === 'claude') {
        proc = spawn('claude', ['--print', '--dangerously-skip-permissions', '-p', prompt], {
            cwd: workspace,
            stdio: ['ignore', 'pipe', 'pipe'],
            env: { ...process.env },
        });
    }
    else {
        proc = spawn('codex', ['--print', '-p', prompt], {
            cwd: workspace,
            stdio: ['ignore', 'pipe', 'pipe'],
            env: { ...process.env },
        });
    }
    const session = {
        process: proc,
        lastActivity: new Date(),
        workspace,
        runtime,
        claudeSessionId: null,
        history: [{ role: 'user', content: message }],
        outputBuffer: '',
    };
    // Capture output for history
    proc.stdout?.on('data', (chunk) => {
        session.outputBuffer += chunk.toString('utf8');
    });
    proc.on('close', () => {
        if (session.outputBuffer.length > 0) {
            session.history.push({ role: 'assistant', content: session.outputBuffer });
        }
        // Try to capture Claude session ID from stderr
        // Claude prints session info to stderr in some modes
    });
    sessions.set(sessionId, session);
    startReaper();
    return session;
}
function chainSession(_sessionId, existing, message) {
    existing.history.push({ role: 'user', content: message });
    // Keep only the last 10 turns to avoid exceeding CLI prompt limits
    const recentHistory = existing.history.slice(-10);
    const historyPrompt = recentHistory
        .map((h) => `[${h.role === 'user' ? 'Human' : 'Assistant'}]: ${h.content}`)
        .join('\n\n');
    const prompt = `Continue this conversation. Here is the history:\n\n${historyPrompt}`;
    let proc;
    if (existing.runtime === 'claude') {
        proc = spawn('claude', ['--print', '--dangerously-skip-permissions', '-p', prompt], {
            cwd: existing.workspace,
            stdio: ['ignore', 'pipe', 'pipe'],
            env: { ...process.env },
        });
    }
    else {
        proc = spawn('codex', ['--print', '-p', prompt], {
            cwd: existing.workspace,
            stdio: ['ignore', 'pipe', 'pipe'],
            env: { ...process.env },
        });
    }
    existing.process = proc;
    existing.lastActivity = new Date();
    existing.outputBuffer = '';
    proc.stdout?.on('data', (chunk) => {
        existing.outputBuffer += chunk.toString('utf8');
    });
    proc.on('close', () => {
        if (existing.outputBuffer.length > 0) {
            existing.history.push({ role: 'assistant', content: existing.outputBuffer });
        }
    });
    return existing;
}
export function getSession(sessionId) {
    return sessions.get(sessionId);
}
export function getSessionHistory(sessionId) {
    return sessions.get(sessionId)?.history ?? [];
}
export function touchSession(sessionId) {
    const session = sessions.get(sessionId);
    if (session) {
        session.lastActivity = new Date();
    }
}
export function kill(sessionId) {
    const session = sessions.get(sessionId);
    if (!session)
        return false;
    try {
        session.process.kill('SIGTERM');
    }
    catch {
        // process already exited
    }
    sessions.delete(sessionId);
    return true;
}
export function cleanup() {
    for (const [id] of sessions) {
        kill(id);
    }
    if (reaperInterval) {
        clearInterval(reaperInterval);
        reaperInterval = null;
    }
}
export function getActiveSessionCount() {
    return sessions.size;
}
//# sourceMappingURL=chat-process-manager.js.map