import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const TOOLS_ROOT = resolve(__dirname, "..");
function readTool(name) {
    return readFileSync(resolve(TOOLS_ROOT, name), "utf-8");
}
// ---------------------------------------------------------------------------
// Task 332. Three new MCP tools on the memory plugin:
//   - memory-report-write       (append-only writer; idempotent on
//                                (accountId, title, occurredAt-within-1-min))
//   - memory-report-read-latest (keyword-routed newest match, default limit=1)
//   - memory-report-list        (paginated catalogue, metadata only)
//
// These tests assert source-level contracts the same way the surrounding
// memory-ingest tests do — live Cypher is exercised by the operator-run
// integration test on the laptop.
// ---------------------------------------------------------------------------
describe("memory-report-write contract", () => {
    const src = readTool("memory-report-write.ts");
    it("caps body at 10,000 characters", () => {
        expect(src).toMatch(/MAX_BODY_CHARS\s*=\s*10_?000/);
        expect(src).toMatch(/body exceeds \$\{MAX_BODY_CHARS\} chars/);
    });
    it("idempotency pre-check matches on (accountId, title, occurredAt-within-1-min)", () => {
        expect(src).toMatch(/MATCH\s*\(r:Report\s*\{accountId:\s*\$accountId,\s*title:\s*\$title\}/);
        expect(src).toMatch(/r\.occurredAt\s*>=\s*datetime\(\$occurredAt\)\s*-\s*duration\('PT1M'\)/);
        expect(src).toMatch(/r\.occurredAt\s*<=\s*datetime\(\$occurredAt\)\s*\+\s*duration\('PT1M'\)/);
    });
    it("returns existing nodeId without re-writing when idempotency matches", () => {
        expect(src).toMatch(/created:\s*false/);
        expect(src).toMatch(/idempotencyReason:\s*"same-title-within-minute"/);
    });
    it("falls back to :AdminUser parent when no conversation context is present", () => {
        expect(src).toMatch(/OPTIONAL MATCH \(c:Conversation\)/);
        expect(src).toMatch(/OPTIONAL MATCH \(au:AdminUser \{accountId:\s*\$accountId\}\)/);
        expect(src).toMatch(/coalesce\(c,\s*au\)\s*AS parent/);
    });
    it("refuses the write when no parent resolves (graph-hierarchy doctrine)", () => {
        expect(src).toMatch(/no parent resolved/);
    });
    it("stamps embedding from title + body for later hybrid search", () => {
        expect(src).toMatch(/await embed\(`\$\{title\}\\n\\n\$\{body\}`\)/);
    });
    it("emits the canonical [reports] op=write log line with reportId, keywords, ms", () => {
        expect(src).toMatch(/\[reports\] op=write reportId=\$\{[^}]+\} keywords=\$\{kwCsv\} ms=\$\{ms\}/);
    });
});
describe("memory-report-read-latest contract", () => {
    const src = readTool("memory-report-read-latest.ts");
    it("matches reports whose keywords array contains the requested keyword", () => {
        expect(src).toMatch(/WHERE \$keyword IN r\.keywords/);
    });
    it("orders by occurredAt descending and caps at the requested limit", () => {
        expect(src).toMatch(/ORDER BY r\.occurredAt DESC/);
        expect(src).toMatch(/LIMIT toInteger\(\$limit\)/);
    });
    it("defaults limit to 1 (the spec's primary access pattern)", () => {
        expect(src).toMatch(/DEFAULT_LIMIT\s*=\s*1\b/);
    });
    it("emits the canonical [reports] op=read-latest log line", () => {
        expect(src).toMatch(/\[reports\] op=read-latest reportId=\$\{firstId\} keywords=\$\{keyword\} ms=\$\{ms\} hits=\$\{results\.length\}/);
    });
});
describe("memory-report-list contract", () => {
    const src = readTool("memory-report-list.ts");
    it("returns metadata only — no body — but reports bodyChars per row", () => {
        expect(src).toMatch(/size\(r\.body\) AS bodyChars/);
        expect(src).not.toMatch(/r\.body AS body/);
    });
    it("applies optional keyword filter via $keyword IN r.keywords", () => {
        expect(src).toMatch(/\$keyword IN r\.keywords/);
    });
    it("applies optional exact-match sourceWorkflow filter", () => {
        expect(src).toMatch(/r\.sourceWorkflow = \$sourceWorkflow/);
    });
    it("paginates via offset+limit and surfaces total before paging", () => {
        expect(src).toMatch(/collect\(r\) AS rows,\s*count\(r\) AS total/);
        expect(src).toMatch(/rows\[toInteger\(\$offset\)\.\.toInteger\(\$offset\)\s*\+\s*toInteger\(\$limit\)\]/);
    });
    it("orders newest first", () => {
        expect(src).toMatch(/ORDER BY r\.occurredAt DESC/);
    });
    it("emits the canonical [reports] op=list log line", () => {
        expect(src).toMatch(/\[reports\] op=list reportId=\$\{firstId\} keywords=\$\{kwLog\} ms=\$\{ms\} hits=\$\{results\.length\} total=\$\{total\}/);
    });
});
describe("server registration", () => {
    const indexSrc = readFileSync(resolve(TOOLS_ROOT, "..", "index.ts"), "utf-8");
    it("registers all three tools by name in index.ts", () => {
        expect(indexSrc).toMatch(/"memory-report-write"/);
        expect(indexSrc).toMatch(/"memory-report-read-latest"/);
        expect(indexSrc).toMatch(/"memory-report-list"/);
    });
    it("threads SESSION_NODE_ID into the write tool from the spawn env", () => {
        expect(indexSrc).toMatch(/conversationNodeId:\s*process\.env\.SESSION_NODE_ID/);
    });
    it("gates memory-report-write behind !readOnly but leaves the read tools always-on", () => {
        const writeIdx = indexSrc.indexOf('"memory-report-write"');
        const readLatestIdx = indexSrc.indexOf('"memory-report-read-latest"');
        const listIdx = indexSrc.indexOf('"memory-report-list"');
        const readOnlyBlockStart = indexSrc.indexOf("if (!readOnly) {");
        expect(readOnlyBlockStart).toBeGreaterThan(0);
        expect(readLatestIdx).toBeGreaterThan(0);
        expect(listIdx).toBeGreaterThan(0);
        expect(writeIdx).toBeGreaterThan(0);
        expect(readLatestIdx).toBeLessThan(readOnlyBlockStart);
        expect(listIdx).toBeLessThan(readOnlyBlockStart);
        expect(writeIdx).toBeGreaterThan(readOnlyBlockStart);
    });
});
//# sourceMappingURL=memory-report-tools.test.js.map