import { existsSync } from "node:fs";
import { resolve } from "node:path";
import { getSession } from "../lib/neo4j.js";
import { computeEmbedding } from "../lib/embedding.js";
import cronParser from "cron-parser";
const { parseExpression } = cronParser;
export async function scheduleUpdate(params) {
    const { accountId, eventId, note, skipNext, action, ...updates } = params;
    // Validate: skipNext only applies to recurring events
    if (skipNext) {
        const checkSession = getSession();
        try {
            const check = await checkSession.run(`MATCH (e:Event {eventId: $eventId, accountId: $accountId})
         RETURN e.recurrence AS recurrence, e.nextRun AS nextRun, e.timezone AS timezone`, { eventId, accountId });
            if (check.records.length === 0) {
                throw new Error(`Event not found: ${eventId}`);
            }
            const rec = check.records[0].get("recurrence");
            if (!rec) {
                throw new Error("skipNext can only be used on recurring events");
            }
            // Advance nextRun to skip one occurrence
            const currentNextRun = check.records[0].get("nextRun");
            const tz = check.records[0].get("timezone");
            const interval = parseExpression(rec, {
                currentDate: new Date(currentNextRun),
                tz: tz ?? undefined,
            });
            const newNextRun = interval.next().toISOString();
            const now = new Date().toISOString();
            const skipSession = getSession();
            try {
                await skipSession.run(`MATCH (e:Event {eventId: $eventId, accountId: $accountId})
           SET e.nextRun = $newNextRun,
               e.skipNext = false,
               e.updatedAt = $now,
               e.notes = COALESCE(e.notes, '') + $noteEntry`, {
                    eventId,
                    accountId,
                    newNextRun,
                    now,
                    noteEntry: `\n[${now}] Skipped next occurrence (was ${currentNextRun}, now ${newNextRun})`,
                });
            }
            finally {
                await skipSession.close();
            }
            return;
        }
        finally {
            await checkSession.close();
        }
    }
    // Build SET clause from provided updates
    const setClauses = ["e.updatedAt = $now"];
    const queryParams = {
        eventId,
        accountId,
        now: new Date().toISOString(),
    };
    if (updates.name !== undefined) {
        setClauses.push("e.name = $name");
        queryParams.name = updates.name;
    }
    if (updates.description !== undefined) {
        setClauses.push("e.description = $description");
        queryParams.description = updates.description;
    }
    if (updates.startDate !== undefined) {
        setClauses.push("e.startDate = $startDate");
        queryParams.startDate = updates.startDate;
    }
    if (updates.endDate !== undefined) {
        setClauses.push("e.endDate = $endDate");
        queryParams.endDate = updates.endDate;
    }
    if (updates.location !== undefined) {
        setClauses.push("e.location = $location");
        queryParams.location = updates.location;
    }
    if (updates.eventStatus !== undefined) {
        setClauses.push("e.eventStatus = $eventStatus");
        queryParams.eventStatus = updates.eventStatus;
    }
    if (updates.recurrence !== undefined) {
        // Validate new cron expression
        try {
            const interval = parseExpression(updates.recurrence, {
                currentDate: new Date(),
                tz: updates.timezone ?? undefined,
            });
            const newNextRun = interval.next().toISOString();
            setClauses.push("e.recurrence = $recurrence");
            setClauses.push("e.nextRun = $newNextRun");
            queryParams.recurrence = updates.recurrence;
            queryParams.newNextRun = newNextRun;
        }
        catch (err) {
            throw new Error(`Invalid recurrence expression: "${updates.recurrence}" — ${err instanceof Error ? err.message : String(err)}`);
        }
    }
    if (updates.timezone !== undefined) {
        setClauses.push("e.timezone = $timezone");
        queryParams.timezone = updates.timezone;
    }
    // Action: set, replace, or clear
    if (action === null) {
        // Explicit null = clear the action
        setClauses.push("e.actionPlugin = null");
        setClauses.push("e.actionTool = null");
        setClauses.push("e.actionArgs = null");
    }
    else if (action !== undefined) {
        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}`);
        }
        setClauses.push("e.actionPlugin = $actionPlugin");
        setClauses.push("e.actionTool = $actionTool");
        queryParams.actionPlugin = action.plugin;
        queryParams.actionTool = action.tool;
        if (action.args && Object.keys(action.args).length > 0) {
            setClauses.push("e.actionArgs = $actionArgs");
            queryParams.actionArgs = JSON.stringify(action.args);
        }
        else {
            setClauses.push("e.actionArgs = null");
        }
    }
    if (note) {
        setClauses.push("e.notes = COALESCE(e.notes, '') + $noteEntry");
        queryParams.noteEntry = `\n[${queryParams.now}] ${note}`;
    }
    // Recompute embedding if name or description changed
    if (updates.name !== undefined || updates.description !== undefined) {
        const parts = [`Event: ${updates.name ?? ""}`, updates.description ?? ""].filter(Boolean);
        const embedding = await computeEmbedding(parts.join(" — "));
        if (embedding.length > 0) {
            setClauses.push("e.embedding = $embedding");
            queryParams.embedding = embedding;
        }
    }
    const neo4jSession = getSession();
    try {
        const result = await neo4jSession.run(`MATCH (e:Event {eventId: $eventId, accountId: $accountId})
       SET ${setClauses.join(", ")}
       RETURN e`, queryParams);
        if (result.records.length === 0) {
            throw new Error(`Event not found: ${eventId}`);
        }
    }
    finally {
        await neo4jSession.close();
    }
}
//# sourceMappingURL=schedule-update.js.map