// Task 478 — memory-update-by-name resolves an elementId by (label, name,
// accountId), then delegates to memoryUpdate. Rejection paths surface a
// useful next step (the lookup tuple, or candidate elementIds on ambiguity)
// so the agent never loops.
import { describe, it, expect, beforeEach, vi } from "vitest";
const mockSession = {
    run: vi.fn(),
    close: vi.fn().mockResolvedValue(undefined),
};
vi.mock("../../lib/neo4j.js", () => ({
    getSession: () => mockSession,
}));
vi.mock("../../../../../../lib/graph-trash/dist/index.js", () => ({
    notTrashed: (alias) => `(NOT ${alias}:Trashed)`,
}));
const memoryUpdateMock = vi.fn();
vi.mock("../memory-update.js", () => ({
    memoryUpdate: (args) => memoryUpdateMock(args),
}));
import { memoryUpdateByName } from "../memory-update-by-name.js";
const ACCOUNT_ID = "acct-1";
const CREATED_BY = { agent: undefined, session: undefined, tool: "memory-update-by-name" };
function record(nodeId) {
    return { get: (k) => (k === "nodeId" ? nodeId : undefined) };
}
beforeEach(() => {
    mockSession.run.mockReset();
    mockSession.close.mockClear();
    memoryUpdateMock.mockReset();
});
describe("memory-update-by-name — happy path", () => {
    it("resolves a unique node and delegates to memoryUpdate", async () => {
        mockSession.run.mockResolvedValueOnce({ records: [record("4:org:27")] });
        memoryUpdateMock.mockResolvedValueOnce({ nodeId: "4:org:27", labels: ["Organization"], updated: true });
        const res = await memoryUpdateByName({
            label: "Organization",
            name: "BioSymm Technologies Ltd",
            accountId: ACCOUNT_ID,
            properties: { url: "https://biosymm.example" },
            createdBy: CREATED_BY,
        });
        expect(res).toEqual({ nodeId: "4:org:27", labels: ["Organization"] });
        expect(memoryUpdateMock).toHaveBeenCalledWith({
            nodeId: "4:org:27",
            properties: { url: "https://biosymm.example" },
            accountId: ACCOUNT_ID,
            createdBy: CREATED_BY,
        });
        const [cypher, params] = mockSession.run.mock.calls[0];
        expect(cypher).toContain("MATCH (n:`Organization`");
        expect(cypher).toContain("accountId: $accountId");
        expect(cypher).toContain("name: $name");
        // notTrashed filter applied
        expect(cypher).toContain("(NOT n:Trashed)");
        expect(params).toEqual({ accountId: ACCOUNT_ID, name: "BioSymm Technologies Ltd" });
    });
});
describe("memory-update-by-name — reject paths", () => {
    it("throws 'not found' on zero matches with the lookup tuple in the message", async () => {
        mockSession.run.mockResolvedValueOnce({ records: [] });
        await expect(memoryUpdateByName({
            label: "Organization",
            name: "Nonexistent Co",
            accountId: ACCOUNT_ID,
            properties: { url: "x" },
            createdBy: CREATED_BY,
        })).rejects.toThrow(/no :Organization found with name="Nonexistent Co"/);
        expect(memoryUpdateMock).not.toHaveBeenCalled();
    });
    it("throws 'ambiguous' on multiple matches and surfaces candidate elementIds", async () => {
        mockSession.run.mockResolvedValueOnce({
            records: [record("4:a:1"), record("4:a:2"), record("4:a:3")],
        });
        await expect(memoryUpdateByName({
            label: "Organization",
            name: "Acme",
            accountId: ACCOUNT_ID,
            properties: { url: "x" },
            createdBy: CREATED_BY,
        })).rejects.toThrow(/ambiguous — 3 :Organization rows share name="Acme".*4:a:1, 4:a:2, 4:a:3/s);
        expect(memoryUpdateMock).not.toHaveBeenCalled();
    });
    it("caps surfaced candidates at 5 and reports the remainder count", async () => {
        const ids = ["4:a:1", "4:a:2", "4:a:3", "4:a:4", "4:a:5", "4:a:6"];
        // The Cypher LIMIT is MAX_CANDIDATES + 1 (= 6); the lookup returns 6 ids
        // when at least 6 rows match. The error message must surface 5 + " (and N more)".
        mockSession.run.mockResolvedValueOnce({ records: ids.map(record) });
        await expect(memoryUpdateByName({
            label: "Organization",
            name: "Acme",
            accountId: ACCOUNT_ID,
            properties: { url: "x" },
            createdBy: CREATED_BY,
        })).rejects.toThrow(/4:a:1, 4:a:2, 4:a:3, 4:a:4, 4:a:5 \(and 1 more\)/);
    });
    it("rejects when label is missing", async () => {
        await expect(memoryUpdateByName({
            label: "",
            name: "X",
            accountId: ACCOUNT_ID,
            properties: { url: "x" },
            createdBy: CREATED_BY,
        })).rejects.toThrow(/label is required/);
        expect(mockSession.run).not.toHaveBeenCalled();
    });
    it("rejects when name is missing", async () => {
        await expect(memoryUpdateByName({
            label: "Organization",
            name: "   ",
            accountId: ACCOUNT_ID,
            properties: { url: "x" },
            createdBy: CREATED_BY,
        })).rejects.toThrow(/name is required/);
    });
    it("rejects when properties is empty", async () => {
        await expect(memoryUpdateByName({
            label: "Organization",
            name: "BioSymm",
            accountId: ACCOUNT_ID,
            properties: {},
            createdBy: CREATED_BY,
        })).rejects.toThrow(/properties is required/);
    });
});
//# sourceMappingURL=memory-update-by-name.test.js.map