/**
 * memory-report-write — durable, keyword-routed report persistence (Task 332).
 *
 * Idempotent on (accountId, title, occurredAt-within-same-minute) to absorb
 * accidental double-fires from a workflow dispatcher. Two distinct calls in
 * the same minute with the same title return the existing :Report nodeId
 * instead of creating a second row.
 *
 * Hierarchy: every :Report is parented to either the active
 * :AdminConversation (when SESSION_NODE_ID is set — the typical case
 * for operator-initiated writes from chat) or to the account's :AdminUser
 * as a fallback so the report still satisfies the graph-hierarchy doctrine
 * when written from a non-conversation context (scheduled workflows etc.).
 */
import { randomUUID } from "node:crypto";
import { getSession } from "../lib/neo4j.js";
import { embed } from "../lib/embeddings.js";
const MAX_BODY_CHARS = 10_000;
export async function memoryReportWrite(params) {
    const { accountId, title, body, keywords, sourceWorkflow, occurredAt, conversationNodeId, } = params;
    if (!accountId)
        throw new Error("memory-report-write: accountId is required");
    if (!title || !title.trim())
        throw new Error("memory-report-write: title is required");
    if (body.length > MAX_BODY_CHARS) {
        throw new Error(`memory-report-write: body exceeds ${MAX_BODY_CHARS} chars (got ${body.length})`);
    }
    const occurredAtIso = occurredAt ?? new Date().toISOString();
    const session = getSession();
    const t0 = Date.now();
    try {
        // Idempotency pre-check: same accountId + title + occurredAt within 1 min.
        const existing = await session.run(`MATCH (r:Report {accountId: $accountId, title: $title})
       WHERE r.occurredAt >= datetime($occurredAt) - duration('PT1M')
         AND r.occurredAt <= datetime($occurredAt) + duration('PT1M')
       RETURN elementId(r) AS nodeId, r.reportId AS reportId
       ORDER BY r.occurredAt DESC
       LIMIT 1`, { accountId, title, occurredAt: occurredAtIso });
        if (existing.records.length > 0) {
            const nodeId = existing.records[0].get("nodeId");
            const reportId = existing.records[0].get("reportId");
            const ms = Date.now() - t0;
            const kwCsv = keywords.join(",");
            process.stderr.write(`[reports] op=write reportId=${reportId.slice(0, 8)} keywords=${kwCsv} ms=${ms} idempotent=1\n`);
            return {
                nodeId,
                reportId,
                created: false,
                idempotencyReason: "same-title-within-minute",
            };
        }
        const embedding = await embed(`${title}\n\n${body}`);
        const reportId = randomUUID();
        // Parent edge: prefer active :AdminConversation, fall back to account's :AdminUser.
        // The MATCH-OPTIONAL pattern picks whichever exists; we COALESCE to a single parent
        // and assert it resolved before CREATEing the Report.
        const writeRes = await session.run(`OPTIONAL MATCH (c:Conversation) WHERE elementId(c) = $conversationNodeId
       OPTIONAL MATCH (au:AdminUser {accountId: $accountId})
       WITH coalesce(c, au) AS parent
       WHERE parent IS NOT NULL
       CREATE (r:Report {
         reportId: $reportId,
         accountId: $accountId,
         title: $title,
         body: $body,
         keywords: $keywords,
         sourceWorkflow: $sourceWorkflow,
         occurredAt: datetime($occurredAt),
         createdAt: datetime(),
         updatedAt: datetime(),
         scope: 'admin',
         embedding: $embedding
       })
       CREATE (parent)-[:PRODUCED]->(r)
       RETURN elementId(r) AS nodeId`, {
            reportId,
            accountId,
            title,
            body,
            keywords,
            sourceWorkflow: sourceWorkflow ?? null,
            occurredAt: occurredAtIso,
            embedding,
            conversationNodeId: conversationNodeId ?? null,
        });
        if (writeRes.records.length === 0) {
            throw new Error(`memory-report-write: no parent resolved (conversationNodeId='${conversationNodeId ?? "<none>"}' and :AdminUser missing for account '${accountId}'). Report not written.`);
        }
        const nodeId = writeRes.records[0].get("nodeId");
        const ms = Date.now() - t0;
        const kwCsv = keywords.join(",");
        process.stderr.write(`[reports] op=write reportId=${reportId.slice(0, 8)} keywords=${kwCsv} ms=${ms}\n`);
        return { nodeId, reportId, created: true };
    }
    finally {
        await session.close();
    }
}
//# sourceMappingURL=memory-report-write.js.map