import { describe, expect, it, beforeEach, afterEach } from "vitest";
import { mkdtemp, rm, readFile, mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { appendManualSessionMessages, appendTranscriptEvents, appendTranscriptEvent, nextTranscriptSeq, readTranscriptEvents, transcriptPath, } from "../interaction/session-transcript.js";
import { restoreAgentMessagesFromTranscript } from "../interaction/session-transcript-restore.js";
describe("session transcript codec", () => {
    let projectRoot;
    beforeEach(async () => {
        projectRoot = await mkdtemp(join(tmpdir(), "inkos-transcript-"));
    });
    afterEach(async () => {
        await rm(projectRoot, { recursive: true, force: true });
    });
    it("一行写入一个 JSON event 并保留 raw AgentMessage 字段", async () => {
        const started = {
            type: "request_started",
            version: 1,
            sessionId: "s1",
            requestId: "r1",
            seq: 1,
            timestamp: 100,
            input: "继续写",
        };
        const message = {
            type: "message",
            version: 1,
            sessionId: "s1",
            requestId: "r1",
            uuid: "m1",
            parentUuid: null,
            seq: 2,
            role: "assistant",
            timestamp: 101,
            message: {
                role: "assistant",
                content: [
                    { type: "thinking", thinking: "推理", signature: "sig-1" },
                    { type: "text", text: "正文" },
                ],
                provider: "anthropic",
                api: "anthropic-messages",
                model: "claude",
                usage: {
                    input: 1,
                    output: 2,
                    cacheRead: 0,
                    cacheWrite: 0,
                    totalTokens: 3,
                    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
                },
                stopReason: "stop",
                timestamp: 101,
            },
        };
        await appendTranscriptEvent(projectRoot, started);
        await appendTranscriptEvent(projectRoot, message);
        const raw = await readFile(transcriptPath(projectRoot, "s1"), "utf-8");
        expect(raw.trim().split("\n")).toHaveLength(2);
        const events = await readTranscriptEvents(projectRoot, "s1");
        expect(events).toHaveLength(2);
        expect(events[1].message).toMatchObject({
            role: "assistant",
            content: [
                { type: "thinking", thinking: "推理", signature: "sig-1" },
                { type: "text", text: "正文" },
            ],
        });
    });
    it("跳过坏行并保留合法 event", async () => {
        const dir = join(projectRoot, ".inkos", "sessions");
        await mkdir(dir, { recursive: true });
        await writeFile(join(dir, "s1.jsonl"), [
            JSON.stringify({
                type: "request_started",
                version: 1,
                sessionId: "s1",
                requestId: "r1",
                seq: 1,
                timestamp: 1,
                input: "hi",
            }),
            "{bad json",
            JSON.stringify({
                type: "request_committed",
                version: 1,
                sessionId: "s1",
                requestId: "r1",
                seq: 2,
                timestamp: 2,
            }),
        ].join("\n"));
        const events = await readTranscriptEvents(projectRoot, "s1");
        expect(events.map((event) => event.type)).toEqual(["request_started", "request_committed"]);
    });
    it("按已有 transcript 分配单调递增 seq", async () => {
        const committed = {
            type: "request_committed",
            version: 1,
            sessionId: "s1",
            requestId: "r1",
            seq: 7,
            timestamp: 100,
        };
        await appendTranscriptEvent(projectRoot, committed);
        await expect(nextTranscriptSeq(projectRoot, "s1")).resolves.toBe(8);
    });
    it("atomically assigns unique seq for concurrent generated events", async () => {
        await Promise.all(Array.from({ length: 10 }, (_, index) => appendTranscriptEvents(projectRoot, "s-concurrent", ({ nextSeq }) => [{
                type: "request_started",
                version: 1,
                sessionId: "s-concurrent",
                requestId: `r-${index}`,
                seq: nextSeq,
                timestamp: 100 + index,
                input: `input-${index}`,
            }])));
        const events = await readTranscriptEvents(projectRoot, "s-concurrent");
        expect(events).toHaveLength(10);
        expect(events.map((event) => event.seq)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });
    it("appendManualSessionMessages 写入 committed request 并保留 raw assistant message", async () => {
        await appendManualSessionMessages(projectRoot, "s1", [{
                role: "assistant",
                content: [{ type: "text", text: "fallback" }],
                api: "anthropic-messages",
                provider: "anthropic",
                model: "fake",
                usage: {
                    input: 0,
                    output: 0,
                    cacheRead: 0,
                    cacheWrite: 0,
                    totalTokens: 0,
                    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
                },
                stopReason: "stop",
                timestamp: 10,
            }], "fallback-input");
        const events = await readTranscriptEvents(projectRoot, "s1");
        expect(events.map((event) => event.type)).toEqual([
            "request_started",
            "message",
            "request_committed",
        ]);
        expect(events[0]).toMatchObject({ type: "request_started", input: "fallback-input" });
        const restored = await restoreAgentMessagesFromTranscript(projectRoot, "s1");
        expect(restored).toMatchObject([
            { role: "assistant", content: [{ type: "text", text: "fallback" }] },
        ]);
    });
    it("从 core index 导出 transcript helper", async () => {
        const core = await import("../index.js");
        expect(typeof core.readTranscriptEvents).toBe("function");
        expect(typeof core.restoreAgentMessagesFromTranscript).toBe("function");
        expect(typeof core.TranscriptEventSchema.safeParse).toBe("function");
    });
});
//# sourceMappingURL=session-transcript.test.js.map