import { mkdtemp, mkdir, readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeAll, describe, expect, it, vi } from "vitest";
import { createLogger } from "../index.js";
import { buildChapterFileLookup, createInteractionToolsFromDeps, } from "../interaction/project-tools.js";
let projectRoot;
describe("interaction tools", () => {
    beforeAll(async () => {
        projectRoot = await mkdtemp(join(tmpdir(), "inkos-core-interaction-tools-"));
        await mkdir(join(projectRoot, "books", "harbor", "story"), { recursive: true });
    });
    it("delegates writeNextChapter and reviseDraft to the pipeline", async () => {
        const events = [];
        const sink = {
            write(entry) {
                events.push(entry.message);
            },
        };
        const pipeline = {
            config: {
                logger: createLogger({ tag: "test", sinks: [sink] }),
            },
            writeNextChapter: vi.fn(async () => ({
                config: undefined,
                chapterNumber: 1,
                title: "Draft",
                wordCount: 1000,
                revised: false,
                status: "ready-for-review",
                auditResult: { passed: true, issues: [], summary: "ok" },
            })),
            reviseDraft: vi.fn(async () => ({
                chapterNumber: 3,
                wordCount: 1200,
                fixedIssues: [],
                applied: true,
                status: "ready-for-review",
            })),
        };
        const state = {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(async () => ({
                id: "harbor",
                title: "Harbor",
                platform: "other",
                genre: "other",
                status: "outlining",
                targetChapters: 200,
                chapterWordCount: 3000,
                createdAt: "2026-04-10T00:00:00.000Z",
                updatedAt: "2026-04-10T00:00:00.000Z",
            })),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => ["harbor"]),
        };
        const tools = createInteractionToolsFromDeps(pipeline, state);
        const writeResult = await tools.writeNextChapter("harbor");
        await tools.reviseDraft("harbor", 3, "rewrite");
        expect(pipeline.writeNextChapter).toHaveBeenCalledWith("harbor");
        expect(pipeline.reviseDraft).toHaveBeenCalledWith("harbor", 3, "rewrite");
        expect(writeResult.__interaction?.activeChapterNumber).toBe(1);
        expect(events).toEqual([]);
    });
    it("captures pipeline stage logs into interaction events", async () => {
        const pipeline = {
            config: {
                logger: createLogger({
                    tag: "test",
                    sinks: [{
                            write() { },
                        }],
                }),
            },
            writeNextChapter: vi.fn(async function () {
                this.config.logger?.info("Stage: preparing chapter inputs");
                this.config.logger?.info("Stage: writing chapter draft");
                return {
                    chapterNumber: 4,
                    title: "Draft",
                    wordCount: 1000,
                    revised: false,
                    status: "ready-for-review",
                    auditResult: { passed: true, issues: [], summary: "ok" },
                };
            }),
            reviseDraft: vi.fn(async () => ({
                chapterNumber: 3,
                wordCount: 1200,
                fixedIssues: [],
                applied: true,
                status: "ready-for-review",
            })),
        };
        const state = {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(async () => ({
                id: "harbor",
                title: "Harbor",
                platform: "other",
                genre: "other",
                status: "outlining",
                targetChapters: 200,
                chapterWordCount: 3000,
                createdAt: "2026-04-10T00:00:00.000Z",
                updatedAt: "2026-04-10T00:00:00.000Z",
            })),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => ["harbor"]),
        };
        const tools = createInteractionToolsFromDeps(pipeline, state);
        const result = await tools.writeNextChapter("harbor");
        expect(result.__interaction?.events).toEqual([
            expect.objectContaining({ kind: "stage.changed", status: "planning", detail: "preparing chapter inputs" }),
            expect.objectContaining({ kind: "stage.changed", status: "writing", detail: "writing chapter draft" }),
        ]);
    });
    it("writes current_focus and author_intent into canonical story paths", async () => {
        const tools = createInteractionToolsFromDeps({
            writeNextChapter: vi.fn(async () => ({
                chapterNumber: 1,
                title: "Draft",
                wordCount: 1000,
                revised: false,
                status: "ready-for-review",
                auditResult: { passed: true, issues: [], summary: "ok" },
            })),
            reviseDraft: vi.fn(async () => ({
                chapterNumber: 3,
                wordCount: 1200,
                fixedIssues: [],
                applied: true,
                status: "ready-for-review",
            })),
        }, {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(async () => ({
                id: "harbor",
                title: "Harbor",
                platform: "other",
                genre: "other",
                status: "outlining",
                targetChapters: 200,
                chapterWordCount: 3000,
                createdAt: "2026-04-10T00:00:00.000Z",
                updatedAt: "2026-04-10T00:00:00.000Z",
            })),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => ["harbor"]),
        });
        await tools.updateCurrentFocus("harbor", "# Current Focus\n\nBring focus back.\n");
        await tools.updateAuthorIntent("harbor", "# Author Intent\n\nWrite a harbor mystery.\n");
        await expect(readFile(join(projectRoot, "books", "harbor", "story", "current_focus.md"), "utf-8"))
            .resolves.toContain("Bring focus back");
        await expect(readFile(join(projectRoot, "books", "harbor", "story", "author_intent.md"), "utf-8"))
            .resolves.toContain("harbor mystery");
    });
    it("rejects truth-file writes outside the canonical truth-file allowlist", async () => {
        const tools = createInteractionToolsFromDeps({
            writeNextChapter: vi.fn(async () => ({
                chapterNumber: 1,
                title: "Draft",
                wordCount: 1000,
                revised: false,
                status: "ready-for-review",
                auditResult: { passed: true, issues: [], summary: "ok" },
            })),
            reviseDraft: vi.fn(async () => ({
                chapterNumber: 3,
                wordCount: 1200,
                fixedIssues: [],
                applied: true,
                status: "ready-for-review",
            })),
        }, {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(async () => ({
                id: "harbor",
                title: "Harbor",
                platform: "other",
                genre: "other",
                status: "outlining",
                targetChapters: 200,
                chapterWordCount: 3000,
                createdAt: "2026-04-10T00:00:00.000Z",
                updatedAt: "2026-04-10T00:00:00.000Z",
            })),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => ["harbor"]),
        });
        await expect(tools.writeTruthFile("harbor", "runtime/agent_notes.md", "notes"))
            .rejects.toThrow("Invalid truth file name");
    });
    it("forwards foundation draft fields into shared book creation", async () => {
        const pipeline = {
            initBook: vi.fn(async () => undefined),
            writeNextChapter: vi.fn(async () => ({
                chapterNumber: 1,
                title: "Draft",
                wordCount: 1000,
                revised: false,
                status: "ready-for-review",
                auditResult: { passed: true, issues: [], summary: "ok" },
            })),
            reviseDraft: vi.fn(async () => ({
                chapterNumber: 3,
                wordCount: 1200,
                fixedIssues: [],
                applied: true,
                status: "ready-for-review",
            })),
        };
        const state = {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(async () => ({
                id: "night-harbor",
                title: "Night Harbor",
                platform: "other",
                genre: "urban",
                status: "outlining",
                targetChapters: 120,
                chapterWordCount: 2800,
                createdAt: "2026-04-10T00:00:00.000Z",
                updatedAt: "2026-04-10T00:00:00.000Z",
            })),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => []),
        };
        const tools = createInteractionToolsFromDeps(pipeline, state);
        await tools.createBook?.({
            title: "Night Harbor",
            genre: "urban",
            platform: "tomato",
            chapterWordCount: 2800,
            targetChapters: 120,
            blurb: "一个做灰产生意的人，准备在夜港洗白，却先被旧账拖回去。",
            worldPremise: "近未来架空香港，港口账本牵出多方势力。",
            protagonist: "林砚，水货账房出身，聪明克制，不轻易信人。",
            conflictCore: "洗白与旧债回潮的对撞。",
            volumeOutline: "卷一先查账，再暴露港口旧案。",
            authorIntent: "# 作者意图\n\n写成冷硬、克制、利益驱动的商战悬疑。\n",
            currentFocus: "# 当前聚焦\n\n先把旧账线和港口势力网立住。\n",
        });
        expect(pipeline.initBook).toHaveBeenCalledWith(expect.objectContaining({
            title: "Night Harbor",
            genre: "urban",
            platform: "tomato",
            targetChapters: 120,
            chapterWordCount: 2800,
        }), expect.objectContaining({
            externalContext: expect.stringContaining("近未来架空香港"),
            authorIntent: expect.stringContaining("冷硬、克制"),
            currentFocus: expect.stringContaining("旧账线"),
        }));
    });
    it("normalizes human-facing platform aliases before creating a book", async () => {
        const pipeline = {
            initBook: vi.fn(async () => undefined),
            writeNextChapter: vi.fn(),
            reviseDraft: vi.fn(),
        };
        const state = {
            ensureControlDocuments: vi.fn(async () => { }),
            bookDir: vi.fn((bookId) => join(projectRoot, "books", bookId)),
            loadBookConfig: vi.fn(),
            loadChapterIndex: vi.fn(async () => []),
            saveChapterIndex: vi.fn(async () => undefined),
            listBooks: vi.fn(async () => []),
        };
        const tools = createInteractionToolsFromDeps(pipeline, state);
        await tools.createBook?.({
            title: "测试书",
            genre: "urban",
            platform: "番茄小说",
        });
        expect(pipeline.initBook).toHaveBeenCalledWith(expect.objectContaining({
            id: "测试书",
            platform: "tomato",
        }), expect.any(Object));
    });
    it("builds a reusable chapter lookup from a single directory listing", () => {
        const lookup = buildChapterFileLookup([
            "0001_First.md",
            "0002_Second.md",
            "notes.txt",
            "0002_Second.backup",
        ]);
        expect(lookup.get(1)).toBe("0001_First.md");
        expect(lookup.get(2)).toBe("0002_Second.md");
        expect(lookup.size).toBe(2);
    });
});
//# sourceMappingURL=interaction-tools.test.js.map