import { randomUUID } from "node:crypto";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
import { getSession } from "../lib/neo4j.js";
import { computeEmbedding } from "../lib/embedding.js";
import { writeNodeWithEdges, } from "../../../../../lib/graph-write/dist/index.js";
import cronParser from "cron-parser";
const { parseExpression } = cronParser;
export async function scheduleEvent(params) {
    const { accountId, name, description, startDate, endDate, location, recurrence, timezone, sessionKey, action, createdBy, } = params;
    if (action) {
        if (!action.plugin || !action.tool) {
            throw new Error("Action requires both 'plugin' and 'tool' fields");
        }
        const platformRoot = process.env.PLATFORM_ROOT;
        if (!platformRoot) {
            throw new Error("PLATFORM_ROOT environment variable is required to validate action plugin");
        }
        const pluginsRoot = resolve(platformRoot, "plugins");
        const pluginDir = resolve(pluginsRoot, action.plugin);
        if (!pluginDir.startsWith(pluginsRoot + "/")) {
            throw new Error(`Invalid action plugin name: ${action.plugin}`);
        }
        if (!existsSync(pluginDir)) {
            throw new Error(`Action plugin directory not found: ${action.plugin}`);
        }
        const pluginMd = resolve(pluginDir, "PLUGIN.md");
        if (!existsSync(pluginMd)) {
            throw new Error(`Action plugin has no PLUGIN.md: ${action.plugin}`);
        }
    }
    let nextRun;
    if (recurrence) {
        try {
            const interval = parseExpression(recurrence, {
                currentDate: new Date(startDate),
                tz: timezone,
            });
            nextRun = interval.next().toISOString();
        }
        catch (err) {
            throw new Error(`Invalid recurrence expression: "${recurrence}" — ${err instanceof Error ? err.message : String(err)}`);
        }
    }
    const eventId = randomUUID();
    const now = new Date().toISOString();
    const props = {
        eventId,
        accountId,
        name,
        startDate,
        eventStatus: "scheduled",
        createdAt: now,
        updatedAt: now,
    };
    if (description)
        props.description = description;
    if (endDate)
        props.endDate = endDate;
    if (location)
        props.location = location;
    if (recurrence)
        props.recurrence = recurrence;
    if (timezone)
        props.timezone = timezone;
    if (nextRun)
        props.nextRun = nextRun;
    if (action) {
        props.actionPlugin = action.plugin;
        props.actionTool = action.tool;
        if (action.args && Object.keys(action.args).length > 0) {
            props.actionArgs = JSON.stringify(action.args);
        }
    }
    const parts = [`Event: ${name}`];
    if (description)
        parts.push(description);
    parts.push(`starts: ${startDate}`);
    if (recurrence)
        parts.push(`recurs: ${recurrence}`);
    if (location)
        parts.push(`at: ${location}`);
    if (action)
        parts.push(`action: ${action.plugin}/${action.tool}`);
    const embedding = await computeEmbedding(parts.join(" — "));
    if (embedding.length > 0)
        props.embedding = embedding;
    // Write doctrine: an Event must link to its owning Conversation
    // (preferred) or be explicitly linked via an upstream elementId. An Event
    // with no adjacency is noise — calendar history with no session / invitee /
    // owner produces nothing queryable.
    const relationships = [];
    const neo4jSession = getSession();
    try {
        if (sessionKey) {
            const r = await neo4jSession.run(`MATCH (c:Conversation {sessionId: $sessionKey}) RETURN elementId(c) AS id LIMIT 1`, { sessionKey });
            if (r.records.length > 0) {
                relationships.push({
                    type: "PART_OF",
                    direction: "outgoing",
                    targetNodeId: r.records[0].get("id"),
                });
            }
        }
        if (relationships.length === 0) {
            throw new Error("Write doctrine violated: schedule-event requires an admin session with an existing Conversation to link the Event (PART_OF). Invoke from inside a session.");
        }
        await writeNodeWithEdges({
            session: neo4jSession,
            labels: ["Event"],
            props,
            relationships,
            createdBy,
        });
    }
    finally {
        await neo4jSession.close();
    }
    return { eventId, nextRun };
}
//# sourceMappingURL=schedule-event.js.map