import { logger, } from '@elizaos/core';
import { N8N_WORKFLOW_SERVICE_TYPE } from '../services/index';
import { UnsupportedIntegrationError } from '../types/index';
import { classifyDraftIntent, formatActionResponse } from '../utils/generation';
import { buildConversationContext } from '../utils/context';
const DRAFT_TTL_MS = 30 * 60 * 1000;
function buildFlowChain(connections) {
    const connectionNames = Object.keys(connections);
    if (connectionNames.length === 0) {
        return '';
    }
    const targets = new Set();
    for (const sourceName of connectionNames) {
        for (const outputType of Object.values(connections[sourceName])) {
            for (const conns of outputType) {
                for (const conn of conns) {
                    targets.add(conn.node);
                }
            }
        }
    }
    const startNodes = connectionNames.filter((n) => !targets.has(n));
    const queue = startNodes.length > 0 ? [...startNodes] : [connectionNames[0]];
    const flowParts = [];
    const visited = new Set();
    while (queue.length > 0) {
        const current = queue.shift();
        if (!current || visited.has(current)) {
            continue;
        }
        visited.add(current);
        flowParts.push(current);
        const outputs = connections[current];
        if (outputs) {
            for (const outputType of Object.values(outputs)) {
                for (const conns of outputType) {
                    for (const conn of conns) {
                        queue.push(conn.node);
                    }
                }
            }
        }
    }
    return flowParts.join(' → ');
}
function buildPreviewData(workflow) {
    const creds = new Set();
    for (const node of workflow.nodes) {
        if (node.credentials) {
            for (const c of Object.keys(node.credentials)) {
                creds.add(c);
            }
        }
    }
    return {
        workflowName: workflow.name,
        nodes: workflow.nodes.map((n) => ({
            name: n.name,
            type: n.type.replace('n8n-nodes-base.', ''),
        })),
        flow: buildFlowChain(workflow.connections),
        credentials: [...creds],
        ...(workflow._meta?.assumptions?.length && { assumptions: workflow._meta.assumptions }),
        ...(workflow._meta?.suggestions?.length && { suggestions: workflow._meta.suggestions }),
    };
}
const examples = [
    [
        {
            name: '{{user1}}',
            content: {
                text: 'Create a workflow that sends me Stripe payment summaries every Monday via Gmail',
            },
        },
        {
            name: '{{agent}}',
            content: {
                text: "I'll create an n8n workflow that fetches Stripe payments weekly and emails you a summary via Gmail.",
                actions: ['CREATE_N8N_WORKFLOW'],
            },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: {
                text: 'Build a workflow to notify me on Slack when a new GitHub issue is created',
            },
        },
        {
            name: '{{agent}}',
            content: {
                text: 'Creating a workflow that monitors GitHub for new issues and sends Slack notifications.',
                actions: ['CREATE_N8N_WORKFLOW'],
            },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: {
                text: 'Set up automation to save Gmail attachments to Google Drive',
            },
        },
        {
            name: '{{agent}}',
            content: {
                text: "I'll build an n8n workflow that watches for Gmail attachments and automatically saves them to Google Drive.",
                actions: ['CREATE_N8N_WORKFLOW'],
            },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Yes, deploy it' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow now...', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Looks good, confirm' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow...', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Go ahead and create it' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow...', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Cancel the workflow' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Workflow draft cancelled.', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Actually, use Outlook instead of Gmail' },
        },
        {
            name: '{{agent}}',
            content: {
                text: 'Regenerating the workflow with Outlook...',
                actions: ['CREATE_N8N_WORKFLOW'],
            },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Ok' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow...', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Yes' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow now.', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
    [
        {
            name: '{{user1}}',
            content: { text: 'Do it' },
        },
        {
            name: '{{agent}}',
            content: { text: 'Deploying your workflow...', actions: ['CREATE_N8N_WORKFLOW'] },
        },
    ],
];
export const createWorkflowAction = {
    name: 'CREATE_N8N_WORKFLOW',
    similes: [
        'CREATE_WORKFLOW',
        'BUILD_WORKFLOW',
        'GENERATE_WORKFLOW',
        'MAKE_AUTOMATION',
        'CREATE_AUTOMATION',
        'BUILD_N8N_WORKFLOW',
        'SETUP_WORKFLOW',
        'CONFIRM_WORKFLOW',
        'DEPLOY_WORKFLOW',
        'CANCEL_WORKFLOW',
    ],
    description: 'Generate, preview, and deploy n8n workflows from natural language. ' +
        'Handles the full lifecycle: generate a draft, show preview, then deploy on user confirmation. ' +
        'Also handles modify/cancel of pending drafts. ' +
        'IMPORTANT: When a workflow draft is pending, this action MUST be used for ANY user response ' +
        'about the draft — including "yes", "ok", "deploy it", "cancel", or modification requests. ' +
        'Never reply with text only when a draft is pending.',
    validate: async (runtime) => {
        return !!runtime.getService(N8N_WORKFLOW_SERVICE_TYPE);
    },
    handler: async (runtime, message, state, _options, callback) => {
        const service = runtime.getService(N8N_WORKFLOW_SERVICE_TYPE);
        if (!service) {
            logger.error({ src: 'plugin:n8n-workflow:action:create' }, 'N8n Workflow service not available');
            if (callback) {
                const text = await formatActionResponse(runtime, 'ERROR', {
                    error: 'N8n Workflow service is not available. Check N8N_API_KEY and N8N_HOST.',
                });
                await callback({ text, success: false });
            }
            return { success: false };
        }
        const content = message.content;
        const userText = (content.text ?? '').trim();
        const userId = message.entityId;
        const cacheKey = `workflow_draft:${userId}`;
        const generationContext = buildConversationContext(message, state);
        try {
            let existingDraft = await runtime.getCache(cacheKey);
            if (existingDraft && Date.now() - existingDraft.createdAt > DRAFT_TTL_MS) {
                logger.debug({ src: 'plugin:n8n-workflow:action:create' }, 'Draft expired, clearing cache');
                await runtime.deleteCache(cacheKey);
                existingDraft = undefined;
            }
            if (existingDraft) {
                const intentResult = await classifyDraftIntent(runtime, userText, existingDraft);
                logger.info({ src: 'plugin:n8n-workflow:action:create' }, `Draft intent: ${intentResult.intent} — ${intentResult.reason}`);
                // If the draft was awaiting clarification and the user answered, treat "confirm" as "modify"
                // to regenerate with the user's answers instead of deploying an incomplete draft.
                const effectiveIntent = intentResult.intent === 'confirm' &&
                    existingDraft.workflow._meta?.requiresClarification?.length
                    ? 'modify'
                    : intentResult.intent;
                if (effectiveIntent !== intentResult.intent) {
                    logger.info({ src: 'plugin:n8n-workflow:action:create' }, 'Draft has pending clarification — overriding "confirm" → "modify" to regenerate with user\'s answers');
                }
                switch (effectiveIntent) {
                    case 'confirm': {
                        const result = await service.deployWorkflow(existingDraft.workflow, userId);
                        // Deploy blocked — unresolved credentials
                        if (result.missingCredentials.length > 0) {
                            const text = await formatActionResponse(runtime, 'AUTH_REQUIRED', {
                                connections: result.missingCredentials.map((m) => ({
                                    service: m.credType,
                                    ...(m.authUrl && { authUrl: m.authUrl }),
                                })),
                            });
                            if (callback) {
                                await callback({ text, success: true });
                            }
                            return { success: true, data: { awaitingUserInput: true } };
                        }
                        await runtime.deleteCache(cacheKey);
                        const text = await formatActionResponse(runtime, 'DEPLOY_SUCCESS', {
                            workflowName: result.name,
                            workflowId: result.id,
                            nodeCount: result.nodeCount,
                            active: result.active,
                        });
                        if (callback) {
                            await callback({ text, success: true });
                        }
                        return { success: true, data: result };
                    }
                    case 'cancel': {
                        await runtime.deleteCache(cacheKey);
                        const text = await formatActionResponse(runtime, 'CANCELLED', {
                            workflowName: existingDraft.workflow.name,
                        });
                        if (callback) {
                            await callback({ text, success: true });
                        }
                        return { success: true };
                    }
                    case 'modify': {
                        const modification = intentResult.modificationRequest || userText;
                        logger.info({ src: 'plugin:n8n-workflow:action:create' }, `Modifying draft: ${modification.slice(0, 100)}`);
                        const modifiedWorkflow = await service.modifyWorkflowDraft(existingDraft.workflow, modification);
                        const modifiedDraft = {
                            workflow: modifiedWorkflow,
                            prompt: existingDraft.prompt,
                            userId,
                            createdAt: Date.now(),
                        };
                        await runtime.setCache(cacheKey, modifiedDraft);
                        if (modifiedWorkflow._meta?.requiresClarification?.length) {
                            const text = await formatActionResponse(runtime, 'CLARIFICATION', {
                                questions: modifiedWorkflow._meta.requiresClarification,
                            });
                            if (callback) {
                                await callback({ text, success: true });
                            }
                            return { success: true, data: { awaitingUserInput: true } };
                        }
                        const text = await formatActionResponse(runtime, 'PREVIEW', buildPreviewData(modifiedWorkflow));
                        if (callback) {
                            await callback({ text, success: true });
                        }
                        return { success: true, data: { awaitingUserInput: true } };
                    }
                    case 'new': {
                        if (!userText) {
                            const text = await formatActionResponse(runtime, 'EMPTY_PROMPT', {});
                            if (callback) {
                                await callback({ text, success: false });
                            }
                            await runtime.deleteCache(cacheKey);
                            return { success: false };
                        }
                        await runtime.deleteCache(cacheKey);
                        try {
                            return await generateAndPreview(runtime, service, generationContext, userId, cacheKey, callback);
                        }
                        catch (genError) {
                            logger.warn({ src: 'plugin:n8n-workflow:action:create' }, `New workflow generation failed — restoring previous draft: ${genError instanceof Error ? genError.message : String(genError)}`);
                            await runtime.setCache(cacheKey, existingDraft);
                            const text = await formatActionResponse(runtime, 'PREVIEW', {
                                ...buildPreviewData(existingDraft.workflow),
                                restoredAfterFailure: true,
                            });
                            if (callback) {
                                await callback({ text, success: true });
                            }
                            return { success: true, data: { awaitingUserInput: true } };
                        }
                    }
                    default: {
                        logger.info({ src: 'plugin:n8n-workflow:action:create' }, 'Intent classification unclear — re-showing preview');
                        const text = await formatActionResponse(runtime, 'PREVIEW', buildPreviewData(existingDraft.workflow));
                        if (callback) {
                            await callback({ text, success: true });
                        }
                        return { success: true, data: { awaitingUserInput: true } };
                    }
                }
            }
            if (!userText) {
                const text = await formatActionResponse(runtime, 'EMPTY_PROMPT', {});
                if (callback) {
                    await callback({ text, success: false });
                }
                return { success: false };
            }
            return await generateAndPreview(runtime, service, generationContext, userId, cacheKey, callback);
        }
        catch (error) {
            if (error instanceof UnsupportedIntegrationError) {
                const text = await formatActionResponse(runtime, 'UNSUPPORTED_INTEGRATION', {
                    unsupported: error.unsupportedServices,
                    available: error.availableServices,
                });
                if (callback) {
                    await callback({ text, success: false });
                }
                return { success: false };
            }
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            logger.error({ src: 'plugin:n8n-workflow:action:create' }, `Failed to create workflow: ${errorMessage}`);
            const text = await formatActionResponse(runtime, 'ERROR', { error: errorMessage });
            if (callback) {
                await callback({ text, success: false });
            }
            return { success: false };
        }
    },
    examples,
};
async function generateAndPreview(runtime, service, prompt, userId, cacheKey, callback) {
    logger.info({ src: 'plugin:n8n-workflow:action:create' }, `Generating workflow from prompt: ${prompt.slice(0, 100)}...`);
    const workflow = await service.generateWorkflowDraft(prompt);
    const draft = {
        workflow,
        prompt,
        userId,
        createdAt: Date.now(),
    };
    await runtime.setCache(cacheKey, draft);
    if (workflow._meta?.requiresClarification?.length) {
        const text = await formatActionResponse(runtime, 'CLARIFICATION', {
            questions: workflow._meta.requiresClarification,
        });
        if (callback) {
            await callback({ text, success: true });
        }
        return { success: true, data: { awaitingUserInput: true } };
    }
    const text = await formatActionResponse(runtime, 'PREVIEW', buildPreviewData(workflow));
    if (callback) {
        await callback({ text, success: true });
    }
    return { success: true, data: { awaitingUserInput: true } };
}
//# sourceMappingURL=createWorkflow.js.map