import { describe, it, expect, vi, beforeEach } from "vitest";
// Captured embed inputs so a test can assert document labels embed their
// bounded summary, not the raw body blob.
const captured = { batch: [], single: [] };
vi.mock("../../lib/embeddings.js", () => ({
    embedBatch: vi.fn(async (texts) => {
        captured.batch.push(texts);
        if (texts.some((t) => t.includes("POISON")))
            throw new Error("batch oversize");
        return texts.map(() => [0.1, 0.2]);
    }),
    embed: vi.fn(async (t) => {
        captured.single.push(t);
        if (t.includes("POISON"))
            throw new Error("node embed failed");
        return [0.1, 0.2];
    }),
}));
vi.mock("../../lib/log-ingest.js", () => ({
    withWriteEvent: async (_info, body) => body(),
}));
// Scripted session: count → total; first LIMIT → seeded rows; subsequent
// LIMIT → []. SET queries resolve empty. neo4j.int passthrough is fine.
let limitCalls = 0;
let seededRows = [];
const fakeSession = {
    run: vi.fn(async (q) => {
        if (q.includes("count(n) AS total")) {
            return { records: [{ get: () => ({ toNumber: () => seededRows.length }) }] };
        }
        if (q.includes("LIMIT $batchSize")) {
            limitCalls++;
            const rows = limitCalls === 1 ? seededRows : [];
            return {
                records: rows.map((r) => ({
                    get: (k) => k === "nodeId" ? r.nodeId : k === "nodeLabels" ? r.nodeLabels : r.props,
                })),
            };
        }
        return { records: [] }; // SET queries
    }),
    close: vi.fn(async () => undefined),
};
vi.mock("../../lib/neo4j.js", () => ({ getSession: () => fakeSession }));
async function importReindex() {
    const mod = await import("../memory-reindex.js");
    return mod.memoryReindex;
}
beforeEach(() => {
    limitCalls = 0;
    captured.batch = [];
    captured.single = [];
    fakeSession.run.mockClear();
});
describe("memory-reindex skip-and-continue", () => {
    it("embeds the good nodes, reports the one failing node, and never aborts", async () => {
        seededRows = [
            { nodeId: "n1", nodeLabels: ["Person"], props: { accountId: "a", scope: "shared", givenName: "Alice" } },
            { nodeId: "n2", nodeLabels: ["Person"], props: { accountId: "a", givenName: "Bob" } },
            { nodeId: "n3", nodeLabels: ["Person"], props: { accountId: "a", givenName: "POISON" } },
        ];
        const memoryReindex = await importReindex();
        const result = await memoryReindex("a");
        expect(result.nodesProcessed).toBe(2);
        expect(result.nodesSkipped).toBe(1);
        expect(result.errors).toHaveLength(1);
        expect(result.errors[0]).toContain("n3");
        // n2 had null scope → backfilled to "shared".
        expect(result.scopeBackfilled).toBe(1);
    });
    it("embeds a document label from its summary, not the raw body blob", async () => {
        seededRows = [
            {
                nodeId: "d1",
                nodeLabels: ["KnowledgeDocument"],
                props: { accountId: "a", scope: "shared", summary: "SUMMARYTOKEN", body: "z".repeat(20_000) },
            },
        ];
        const memoryReindex = await importReindex();
        const result = await memoryReindex("a");
        expect(result.nodesProcessed).toBe(1);
        const allTexts = captured.batch.flat().join(" ");
        expect(allTexts).toContain("SUMMARYTOKEN");
        expect(allTexts).not.toContain("zzzz");
    });
});
//# sourceMappingURL=memory-reindex.test.js.map