import { createHash } from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
import { getSession } from "../lib/neo4j.js";
// ---------------------------------------------------------------------------
// email-classify — operator-solicited reclassify for one email-thread
// :KnowledgeDocument keyed by its root Message-ID. Thin wrapper over the
// generic kd-classify primitive (memory plugin): derives the
// account-scoped attachmentId, runs the same body-growth gate, stages the
// thread body to a temp file, and returns a dispatch envelope the admin
// agent uses to hand off to the `librarian` specialist.
//
// The gate threshold and envelope shape mirror
// `platform/plugins/memory/mcp/src/lib/kd-classify-gate.ts`; the two copies
// are duplicated rather than cross-plugin-imported so each MCP process boots
// independently. Keep both aligned when the contract changes. Task 401.
// ---------------------------------------------------------------------------
const KD_CLASSIFY_GROWTH_THRESHOLD = 0.25;
function deriveThreadAttachmentId(accountId, rootMessageId) {
    return createHash("sha256")
        .update(`email:${accountId}:${rootMessageId}`)
        .digest("hex");
}
async function readThread(accountId, attachmentId) {
    const session = getSession();
    try {
        const result = await session.run(`MATCH (kd:KnowledgeDocument { source: 'email', accountId: $accountId, attachmentId: $attachmentId })
       RETURN coalesce(size(kd.body), 0) AS bodyLen,
              coalesce(kd.lastClassifiedBodyLength, 0) AS lastLen,
              kd.body AS body`, { accountId, attachmentId });
        if (result.records.length === 0)
            return null;
        const r = result.records[0];
        return {
            bodyLen: Number(r.get("bodyLen")),
            lastClassifiedBodyLength: Number(r.get("lastLen")),
            body: r.get("body") ?? "",
        };
    }
    finally {
        await session.close();
    }
}
export async function emailClassify(params) {
    const { accountId, rootMessageId } = params;
    if (!rootMessageId.trim()) {
        throw new Error("email-classify: rootMessageId is required.");
    }
    const attachmentId = deriveThreadAttachmentId(accountId, rootMessageId);
    const meta = await readThread(accountId, attachmentId);
    if (!meta) {
        throw new Error(`email-classify: no email-thread :KnowledgeDocument for rootMessageId=${rootMessageId} in account ${accountId}. Have you run email-fetch + email-ingest first?`);
    }
    if (meta.bodyLen === 0) {
        throw new Error(`email-classify: thread KD for rootMessageId=${rootMessageId} has empty body; cannot classify.`);
    }
    const lastLen = meta.lastClassifiedBodyLength;
    const growthPct = lastLen > 0 ? (meta.bodyLen - lastLen) / lastLen : 1;
    const isFirstClassify = lastLen <= 0;
    const shouldProceed = isFirstClassify || growthPct >= KD_CLASSIFY_GROWTH_THRESHOLD;
    process.stderr.write(`[email-classify] attachmentId=${attachmentId.slice(0, 12)} bodyLen=${meta.bodyLen} lastLen=${lastLen} growthPct=${growthPct.toFixed(3)} action=${shouldProceed ? "proceed" : "skip"}\n`);
    if (!shouldProceed) {
        const pctRounded = Math.round(growthPct * 100);
        return `no classification needed (body grew ${pctRounded}% since last ingest; threshold ${Math.round(KD_CLASSIFY_GROWTH_THRESHOLD * 100)}%)`;
    }
    const accountDir = process.env.ACCOUNT_DIR;
    if (!accountDir) {
        throw new Error(`email-classify: ACCOUNT_DIR env not set; cannot stage thread body for librarian dispatch.`);
    }
    const tempFilePath = `${accountDir}/tmp/kd-classify-${attachmentId}.txt`;
    await mkdir(dirname(tempFilePath), { recursive: true });
    await writeFile(tempFilePath, meta.body, "utf-8");
    const growthLabel = isFirstClassify
        ? "first classify"
        : `${Math.round(growthPct * 100)}% growth since last ingest`;
    return [
        `Ready to classify email :KnowledgeDocument into sections.`,
        `attachmentId: ${attachmentId}`,
        `rootMessageId: ${rootMessageId}`,
        `bodyLen: ${meta.bodyLen} chars (${growthLabel})`,
        `tempFilePath: ${tempFilePath}`,
        ``,
        `Next: dispatch the \`librarian\` specialist via the Task tool with this brief —`,
        `  "Ingest the document at ${tempFilePath} using mode=document, attachmentId=${attachmentId},`,
        `   anchor=LocalBusiness. The :KnowledgeDocument already exists and has source=email;`,
        `   memory-ingest will MERGE by attachmentId and write :Section children, replacing any prior."`,
    ].join("\n");
}
//# sourceMappingURL=email-classify.js.map