/** Catalogs persisted sessions for listing, lookup, and resume workflows. */
import { existsSync } from 'fs';
import { readdir, readFile, stat } from 'fs/promises';
import { join } from 'path';
import { getSessionsDir } from '../../config.js';
import { getDefaultSessionDir } from './session-paths.js';
function isMessageWithContent(message) {
    return typeof message.role === 'string' && 'content' in message;
}
function extractTextContent(message) {
    const content = message.content;
    if (typeof content === 'string') {
        return content;
    }
    return content
        .filter((block) => block.type === 'text')
        .map((block) => block.text)
        .join(' ');
}
function getLastActivityTime(entries) {
    let lastActivityTime;
    for (const entry of entries) {
        if (entry.type !== 'message')
            continue;
        const message = entry.message;
        if (!isMessageWithContent(message))
            continue;
        if (message.role !== 'user' && message.role !== 'assistant')
            continue;
        const msgTimestamp = message.timestamp;
        if (typeof msgTimestamp === 'number') {
            lastActivityTime = Math.max(lastActivityTime ?? 0, msgTimestamp);
            continue;
        }
        const entryTimestamp = entry.timestamp;
        if (typeof entryTimestamp === 'string') {
            const t = new Date(entryTimestamp).getTime();
            if (!Number.isNaN(t)) {
                lastActivityTime = Math.max(lastActivityTime ?? 0, t);
            }
        }
    }
    return lastActivityTime;
}
function getSessionModifiedDate(entries, header, statsMtime) {
    const lastActivityTime = getLastActivityTime(entries);
    if (typeof lastActivityTime === 'number' && lastActivityTime > 0) {
        return new Date(lastActivityTime);
    }
    const headerTime = typeof header.timestamp === 'string' ? new Date(header.timestamp).getTime() : NaN;
    return !Number.isNaN(headerTime) ? new Date(headerTime) : statsMtime;
}
export async function buildSessionInfo(filePath) {
    try {
        const content = await readFile(filePath, 'utf8');
        const entries = [];
        const lines = content.trim().split('\n');
        for (const line of lines) {
            if (!line.trim())
                continue;
            try {
                entries.push(JSON.parse(line));
            }
            catch {
                // Skip malformed lines
            }
        }
        if (entries.length === 0)
            return null;
        const header = entries[0];
        if (header.type !== 'session')
            return null;
        const stats = await stat(filePath);
        let messageCount = 0;
        let firstMessage = '';
        let lastMessage = '';
        const allMessages = [];
        let name;
        for (const entry of entries) {
            if (entry.type === 'session_info') {
                const infoEntry = entry;
                if (infoEntry.name) {
                    name = infoEntry.name.trim();
                }
            }
            if (entry.type !== 'message')
                continue;
            messageCount++;
            const message = entry.message;
            if (!isMessageWithContent(message))
                continue;
            if (message.role !== 'user' && message.role !== 'assistant')
                continue;
            const textContent = extractTextContent(message);
            if (!textContent)
                continue;
            allMessages.push(textContent);
            if (!firstMessage && message.role === 'user') {
                firstMessage = textContent;
            }
            if (message.role === 'user') {
                lastMessage = textContent;
            }
        }
        const sessionHeader = header;
        const modified = getSessionModifiedDate(entries, sessionHeader, stats.mtime);
        return {
            path: filePath,
            id: sessionHeader.id,
            cwd: typeof sessionHeader.cwd === 'string' ? sessionHeader.cwd : '',
            name,
            parentSessionPath: sessionHeader.parentSession,
            created: new Date(sessionHeader.timestamp),
            modified,
            messageCount,
            firstMessage: firstMessage || '(no messages)',
            lastMessage: lastMessage || firstMessage || '(no messages)',
            allMessagesText: allMessages.join(' ')
        };
    }
    catch {
        return null;
    }
}
export async function listSessionsFromDir(dir, onProgress, progressOffset = 0, progressTotal) {
    const sessions = [];
    if (!existsSync(dir)) {
        return sessions;
    }
    try {
        const dirEntries = await readdir(dir);
        const files = dirEntries.filter((f) => f.endsWith('.jsonl')).map((f) => join(dir, f));
        const total = progressTotal ?? files.length;
        let loaded = 0;
        const results = await Promise.all(files.map(async (file) => {
            const info = await buildSessionInfo(file);
            loaded++;
            onProgress?.(progressOffset + loaded, total);
            return info;
        }));
        for (const info of results) {
            if (info) {
                sessions.push(info);
            }
        }
    }
    catch {
        // Return empty list on error
    }
    return sessions;
}
export async function listSessions(cwd, sessionDir, onProgress) {
    const dir = sessionDir ?? getDefaultSessionDir(cwd);
    const sessions = await listSessionsFromDir(dir, onProgress);
    sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());
    return sessions;
}
export async function listAllSessions(onProgress) {
    const sessionsDir = getSessionsDir();
    try {
        if (!existsSync(sessionsDir)) {
            return [];
        }
        const entries = await readdir(sessionsDir, { withFileTypes: true });
        const dirs = entries.filter((e) => e.isDirectory()).map((e) => join(sessionsDir, e.name));
        let totalFiles = 0;
        const dirFiles = [];
        for (const dir of dirs) {
            try {
                const files = (await readdir(dir)).filter((f) => f.endsWith('.jsonl'));
                dirFiles.push(files.map((f) => join(dir, f)));
                totalFiles += files.length;
            }
            catch {
                dirFiles.push([]);
            }
        }
        let loaded = 0;
        const sessions = [];
        const allFiles = dirFiles.flat();
        const results = await Promise.all(allFiles.map(async (file) => {
            const info = await buildSessionInfo(file);
            loaded++;
            onProgress?.(loaded, totalFiles);
            return info;
        }));
        for (const info of results) {
            if (info) {
                sessions.push(info);
            }
        }
        sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());
        return sessions;
    }
    catch {
        return [];
    }
}
//# sourceMappingURL=session-catalog.js.map