import fsPromises from "node:fs/promises";
import path from "node:path";
import { isSessionEntry } from "./entry-types.js";
import { assertSafeSessionId } from "./session-id.js";
export function createMemorySessionStore(sessionId) {
    assertSafeSessionId(sessionId);
    const entries = [];
    return {
        sessionId,
        async append(entry) {
            entries.push(cloneEntry(entry));
        },
        async list() {
            return entries.map(cloneEntry);
        },
        async dispose() {
            entries.length = 0;
        }
    };
}
export async function createJsonlSessionStore(sessionId, directory, options = {}) {
    assertSafeSessionId(sessionId);
    const fs = options.fs ?? fsPromises;
    const filePath = path.join(directory, `${sessionId}.jsonl`);
    let writeQueue = Promise.resolve();
    await fs.mkdir(directory, { recursive: true });
    return {
        sessionId,
        async append(entry) {
            writeQueue = writeQueue.then(() => fs.appendFile(filePath, `${JSON.stringify(entry)}\n`, "utf8").then(() => undefined));
            await writeQueue;
        },
        async list() {
            await writeQueue;
            let serialized;
            try {
                serialized = String(await fs.readFile(filePath, "utf8"));
            }
            catch (error) {
                if (isMissingFileError(error)) {
                    return [];
                }
                throw error;
            }
            const entries = [];
            const lines = serialized.split("\n");
            for (const [index, line] of lines.entries()) {
                const trimmed = line.trim();
                if (trimmed.length === 0) {
                    continue;
                }
                let parsed;
                try {
                    parsed = JSON.parse(trimmed);
                }
                catch {
                    const isTrailingPartialLine = index === lines.length - 1 && !serialized.endsWith("\n");
                    if (isTrailingPartialLine) {
                        break;
                    }
                    throw new Error(`Unable to parse poe-agent session entry at ${filePath}:${index + 1}.`);
                }
                if (!isSessionEntry(parsed)) {
                    throw new Error(`Invalid poe-agent session entry in ${filePath}.`);
                }
                entries.push(parsed);
            }
            return entries;
        },
        async dispose() {
            await writeQueue;
        }
    };
}
function cloneEntry(entry) {
    return JSON.parse(JSON.stringify(entry));
}
function isMissingFileError(error) {
    return error instanceof Error && "code" in error && error.code === "ENOENT";
}
