import { randomUUID } from "node:crypto";
import { getSession } from "../lib/neo4j.js";
import { embed } from "../lib/embeddings.js";
import { validateCapabilities } from "../lib/validate-capabilities.js";
import { resolveOrder } from "../lib/step-resolver.js";
export async function workflowUpdate(params) {
    const { workflowId, accountId, name, description, steps, status } = params;
    const session = getSession();
    try {
        // Verify workflow exists
        const existing = await session.run(`MATCH (w:Workflow {workflowId: $workflowId, accountId: $accountId})
       RETURN w`, { workflowId, accountId });
        if (existing.records.length === 0) {
            throw new Error(`Workflow not found: ${workflowId}`);
        }
        const now = new Date().toISOString();
        // If steps are provided, replace all step nodes
        if (steps) {
            const stepDefs = steps.map((s, i) => {
                const base = {
                    stepId: randomUUID(),
                    dependsOn: s.dependsOn,
                    onFailure: s.onFailure ?? "abort",
                    retryLimit: s.retryLimit,
                    outputKey: s.outputKey,
                    timeout: s.timeout,
                    position: i,
                    label: s.label,
                };
                if (s.type === "llm") {
                    return {
                        ...base,
                        type: "llm",
                        prompt: s.prompt,
                        model: s.model,
                        maxTokens: s.maxTokens,
                        fallbackMode: s.fallbackMode,
                        fallbackTemplate: s.fallbackTemplate,
                    };
                }
                return { ...base, type: "tool", plugin: s.plugin, tool: s.tool, params: s.params };
            });
            // Resolve numeric dependsOn refs to stepIds
            for (const step of stepDefs) {
                if (!step.dependsOn)
                    continue;
                step.dependsOn = step.dependsOn.map((ref) => {
                    if (ref.length === 36 && ref.includes("-"))
                        return ref;
                    const idx = parseInt(ref, 10);
                    if (!isNaN(idx) && idx >= 0 && idx < stepDefs.length) {
                        return stepDefs[idx].stepId;
                    }
                    return ref;
                });
            }
            // Validate dependency graph
            resolveOrder(stepDefs);
            // Delete old steps, create new ones
            await session.run(`MATCH (w:Workflow {workflowId: $workflowId, accountId: $accountId})-[:HAS_STEP]->(s:WorkflowStep)
         DETACH DELETE s`, { workflowId, accountId });
            for (const step of stepDefs) {
                const baseProps = {
                    stepId: step.stepId,
                    workflowId,
                    accountId,
                    type: step.type,
                    dependsOn: step.dependsOn && step.dependsOn.length > 0
                        ? JSON.stringify(step.dependsOn)
                        : null,
                    onFailure: step.onFailure ?? "abort",
                    retryLimit: step.retryLimit ?? null,
                    outputKey: step.outputKey ?? null,
                    timeout: step.timeout ?? null,
                    position: step.position,
                    label: step.label,
                };
                const typeProps = step.type === "llm"
                    ? {
                        prompt: step.prompt,
                        model: step.model ?? null,
                        maxTokens: step.maxTokens ?? null,
                        fallbackMode: step.fallbackMode ?? null,
                        fallbackTemplate: step.fallbackTemplate ?? null,
                        plugin: null,
                        tool: null,
                        params: null,
                    }
                    : {
                        plugin: step.plugin,
                        tool: step.tool,
                        params: step.params ? JSON.stringify(step.params) : null,
                        prompt: null,
                        model: null,
                        maxTokens: null,
                        fallbackMode: null,
                        fallbackTemplate: null,
                    };
                await session.run(`MATCH (w:Workflow {workflowId: $workflowId})
           CREATE (w)-[:HAS_STEP]->(s:WorkflowStep $props)`, { workflowId, props: { ...baseProps, ...typeProps } });
            }
            // Re-validate capabilities and set status accordingly
            const platformRoot = process.env.PLATFORM_ROOT;
            if (platformRoot) {
                const validation = validateCapabilities(stepDefs, platformRoot);
                const validatedStatus = validation.valid ? (status ?? "active") : "draft";
                await session.run(`MATCH (w:Workflow {workflowId: $workflowId, accountId: $accountId})
           SET w.status = $status, w.updatedAt = $now`, { workflowId, accountId, status: validatedStatus, now });
            }
        }
        // Build SET clauses for non-step fields
        const setClauses = ["w.updatedAt = $updatedAt"];
        const queryParams = {
            workflowId,
            accountId,
            updatedAt: now,
        };
        if (name !== undefined) {
            setClauses.push("w.name = $name");
            queryParams.name = name;
        }
        if (description !== undefined) {
            setClauses.push("w.description = $description");
            queryParams.description = description;
        }
        if (status !== undefined && !steps) {
            // Setting status without new steps — if activating, re-validate
            // existing steps to prevent bypassing capability checks on draft workflows
            if (status === "active") {
                const platformRoot = process.env.PLATFORM_ROOT;
                if (platformRoot) {
                    const stepsResult = await session.run(`MATCH (w:Workflow {workflowId: $workflowId, accountId: $accountId})-[:HAS_STEP]->(s:WorkflowStep)
             RETURN s`, { workflowId, accountId });
                    if (stepsResult.records.length > 0) {
                        const existingSteps = stepsResult.records.map((r) => {
                            const s = r.get("s").properties;
                            return {
                                stepId: s.stepId,
                                type: s.type,
                                plugin: s.plugin,
                                tool: s.tool,
                                position: s.position ?? 0,
                                label: s.label,
                            };
                        });
                        const validation = validateCapabilities(existingSteps, platformRoot);
                        if (!validation.valid) {
                            throw new Error(`Cannot activate workflow — missing capabilities: ${validation.errors.map((e) => e.reason).join("; ")}`);
                        }
                    }
                }
            }
            setClauses.push("w.status = $status");
            queryParams.status = status;
        }
        // Re-embed if name or description changed
        if (name !== undefined || description !== undefined) {
            const current = existing.records[0].get("w").properties;
            const embName = name ?? current.name;
            const embDesc = description ?? current.description;
            const embedding = await embed(`${embName} ${embDesc}`);
            setClauses.push("w.embedding = $embedding");
            queryParams.embedding = embedding;
        }
        if (setClauses.length > 1 || name !== undefined || description !== undefined) {
            await session.run(`MATCH (w:Workflow {workflowId: $workflowId, accountId: $accountId})
         SET ${setClauses.join(", ")}`, queryParams);
        }
    }
    finally {
        await session.close();
    }
}
//# sourceMappingURL=workflow-update.js.map