import { TriggerSuggestionEngine } from './trigger-suggestion-engine.js';
export class ProcessBuilder {
    sessions = new Map();
    store;
    triggerEngine;
    constructor(store) {
        this.store = store;
        this.triggerEngine = new TriggerSuggestionEngine(store);
    }
    // Simple API for tests
    async createProcess(options) {
        if (!options.name || options.name.trim().length === 0) {
            throw new Error('Process name is required');
        }
        const process = {
            id: `process-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
            name: options.name,
            description: options.description || '',
            version: '1.0.0',
            persona: options.persona,
            triggers: options.triggers || [],
            activities: options.activities || [],
            variables: options.variables || {},
            metadata: {
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString(),
                executionCount: 0
            }
        };
        await this.store.saveProcess(process);
        return process;
    }
    async addActivity(processId, activity, position) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        if (position !== undefined && position >= 0 && position <= process.activities.length) {
            process.activities.splice(position, 0, activity);
        }
        else {
            process.activities.push(activity);
        }
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async updateActivity(processId, activityId, updates) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        const activityIndex = process.activities.findIndex(a => a.id === activityId);
        if (activityIndex === -1) {
            throw new Error(`Activity ${activityId} not found`);
        }
        process.activities[activityIndex] = { ...process.activities[activityIndex], ...updates };
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async removeActivity(processId, activityId) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        const originalLength = process.activities.length;
        process.activities = process.activities.filter(a => a.id !== activityId);
        if (process.activities.length === originalLength) {
            throw new Error('Activity not found');
        }
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async addTrigger(processId, trigger) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        // Check for duplicate trigger ID
        if (process.triggers.some(t => t.id === trigger.id)) {
            throw new Error(`Trigger with ID ${trigger.id} already exists`);
        }
        process.triggers.push(trigger);
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async updateTrigger(processId, triggerId, updates) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        const triggerIndex = process.triggers.findIndex(t => t.id === triggerId);
        if (triggerIndex === -1) {
            throw new Error(`Trigger ${triggerId} not found`);
        }
        process.triggers[triggerIndex] = { ...process.triggers[triggerIndex], ...updates };
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async removeTrigger(processId, triggerId) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        process.triggers = process.triggers.filter(t => t.id !== triggerId);
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async cloneProcess(processId, newName, options) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        const cloned = {
            ...process,
            id: `process-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
            name: newName,
            persona: (options?.persona || process.persona),
            // Deep clone activities with new IDs
            activities: process.activities.map(activity => ({
                ...activity,
                id: `${activity.id}-clone-${Date.now()}`
            })),
            // Deep clone triggers with new IDs
            triggers: process.triggers.map(trigger => ({
                ...trigger,
                id: `${trigger.id}-clone-${Date.now()}`
            })),
            // Deep clone variables
            variables: JSON.parse(JSON.stringify(process.variables)),
            metadata: {
                ...process.metadata,
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString(),
                executionCount: 0,
            }
        };
        await this.store.saveProcess(cloned);
        return cloned;
    }
    steps = [
        {
            id: 'name',
            type: 'question',
            prompt: '📝 What would you like to name this process?',
            helpText: 'Choose a descriptive name that explains what the process does',
            validation: (value) => {
                if (!value || value.trim().length < 3) {
                    return 'Process name must be at least 3 characters';
                }
                return true;
            }
        },
        {
            id: 'description',
            type: 'question',
            prompt: '📄 Describe what this process does',
            helpText: 'This helps others understand the purpose of the process'
        },
        {
            id: 'persona',
            type: 'question',
            prompt: '👤 Who is this process for?',
            helpText: 'Choose a persona or type "custom" for general use',
            options: [
                'software-engineer',
                'architect',
                'cto',
                'ceo',
                'cfo',
                'marketing',
                'sales',
                'product-manager',
                'designer',
                'custom'
            ]
        },
        {
            id: 'activities',
            type: 'multiSelect',
            prompt: '📊 What activities should this process include?',
            helpText: 'Select all that apply (we\'ll configure details later)',
            options: [
                'Run automated tools',
                'Wait for human approval',
                'Delegate to AI agents',
                'Make conditional decisions',
                'Loop through items',
                'Call external APIs',
                'Generate reports',
                'Send notifications'
            ]
        },
        {
            id: 'trigger-review',
            type: 'trigger-suggestion',
            prompt: '🎯 Based on your process, here are my trigger recommendations',
            helpText: 'You can accept, modify, or choose alternatives'
        },
        {
            id: 'confirm',
            type: 'confirm',
            prompt: '✅ Ready to create your process?',
            helpText: 'You can always modify the process later'
        }
    ];
    async startProcessBuilder() {
        const session = {
            id: this.generateSessionId(),
            currentStep: 0,
            processData: {},
            responses: {}
        };
        this.sessions.set(session.id, session);
        return session;
    }
    async continueBuilder(sessionId, response) {
        const session = this.sessions.get(sessionId);
        if (!session) {
            return { valid: false, message: 'Session not found' };
        }
        const currentStep = this.steps[session.currentStep];
        // Validate response
        if (currentStep.validation) {
            const validationResult = currentStep.validation(response);
            if (validationResult !== true) {
                return {
                    valid: false,
                    message: typeof validationResult === 'string' ? validationResult : 'Invalid response'
                };
            }
        }
        // Store response
        session.responses[currentStep.id] = response;
        // Process based on step type
        if (currentStep.type === 'trigger-suggestion') {
            // User selected a trigger configuration
            if (response.selectedTrigger) {
                session.processData.triggers = [response.selectedTrigger];
            }
        }
        // Move to next step
        session.currentStep++;
        // Check if we need to prepare trigger suggestions
        if (session.currentStep < this.steps.length) {
            const nextStep = this.steps[session.currentStep];
            if (nextStep.type === 'trigger-suggestion') {
                // Generate trigger suggestions based on collected data
                const tempProcess = this.buildProcessFromSession(session);
                const suggestions = await this.triggerEngine.suggestTriggers(tempProcess);
                session.suggestedTriggers = suggestions.map(s => s.trigger);
            }
        }
        // Check if complete
        if (session.currentStep >= this.steps.length) {
            const process = this.buildProcessFromSession(session);
            this.sessions.delete(sessionId);
            return {
                valid: true,
                completed: true,
                process
            };
        }
        return { valid: true };
    }
    formatCurrentStep(sessionId) {
        const session = this.sessions.get(sessionId);
        if (!session) {
            return 'Session not found';
        }
        const step = this.steps[session.currentStep];
        const progress = `Step ${session.currentStep + 1} of ${this.steps.length}`;
        let output = `${progress}\n\n${step.prompt}\n`;
        if (step.helpText) {
            output += `💡 ${step.helpText}\n`;
        }
        if (step.type === 'trigger-suggestion' && session.suggestedTriggers) {
            output += '\n';
            session.suggestedTriggers.forEach((trigger, index) => {
                output += `\n${index + 1}. **${trigger.name}**\n`;
                output += `   Type: ${trigger.type}\n`;
                if (trigger.type === 'schedule' && trigger.config.cron) {
                    output += `   Schedule: ${trigger.config.cron}\n`;
                }
                if (trigger.reasoning) {
                    output += `   📝 ${trigger.reasoning}\n`;
                }
            });
            output += '\nWhich trigger would you like to use? (number or "custom" for manual setup)';
        }
        else if (step.options) {
            output += '\nOptions:\n';
            step.options.forEach((option, index) => {
                output += `${index + 1}. ${option}\n`;
            });
        }
        return output;
    }
    cancelSession(sessionId) {
        this.sessions.delete(sessionId);
    }
    buildProcessFromSession(session) {
        const responses = session.responses;
        // Build activities based on selections
        const activities = [];
        const activitySelections = responses.activities || [];
        // Map selections to basic activity templates
        if (activitySelections.includes('Run automated tools')) {
            activities.push({
                id: 'tool-1',
                type: 'tool',
                name: 'Execute Tool',
                config: {
                    toolName: 'check_project_status',
                    toolArgs: {}
                }
            });
        }
        if (activitySelections.includes('Wait for human approval')) {
            activities.push({
                id: 'human-1',
                type: 'human',
                name: 'Human Approval',
                config: {
                    prompt: 'Please review and approve',
                    approvalType: 'any'
                }
            });
        }
        if (activitySelections.includes('Generate reports')) {
            activities.push({
                id: 'tool-2',
                type: 'tool',
                name: 'Generate Report',
                config: {
                    toolName: 'generate_report',
                    toolArgs: {}
                }
            });
        }
        const process = {
            id: this.generateId('process'),
            name: responses.name || 'Unnamed Process',
            description: responses.description,
            version: '1.0.0',
            persona: responses.persona,
            triggers: session.processData.triggers || [],
            activities,
            variables: {},
            metadata: {
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString(),
                executionCount: 0
            }
        };
        return process;
    }
    generateSessionId() {
        return `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
    }
    generateId(prefix) {
        return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
    }
    // Additional methods for test compatibility
    async setVariables(processId, variables, merge = false) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        if (merge) {
            // Merge variables with existing ones
            process.variables = {
                ...process.variables,
                ...variables
            };
        }
        else {
            // Replace all variables
            process.variables = variables;
        }
        process.metadata.updatedAt = new Date().toISOString();
        await this.store.saveProcess(process);
        return process;
    }
    async validateProcess(processId) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            return {
                isValid: false,
                errors: [{ type: 'error', message: `Process ${processId} not found` }],
                warnings: []
            };
        }
        const errors = [];
        const warnings = [];
        // Validate required fields
        if (!process.name || process.name.trim().length === 0) {
            errors.push({ type: 'error', field: 'name', message: 'Process name is required' });
        }
        if (!process.id) {
            errors.push({ type: 'error', field: 'id', message: 'Process ID is required' });
        }
        // Validate activities
        if (!process.activities || process.activities.length === 0) {
            warnings.push({ type: 'warning', message: 'Process has no activities defined' });
        }
        else {
            // Validate each activity
            process.activities.forEach((activity, index) => {
                if (!activity.id) {
                    errors.push({
                        type: 'error',
                        field: `activities[${index}].id`,
                        message: `Activity at index ${index} is missing ID`
                    });
                }
                if (!activity.type) {
                    errors.push({
                        type: 'error',
                        field: `activities[${index}].type`,
                        message: `Activity ${activity.id || index} is missing type`
                    });
                }
                if (!activity.name) {
                    errors.push({
                        type: 'error',
                        field: `activities[${index}].name`,
                        message: `Activity ${activity.id || index} is missing name`
                    });
                }
                // Validate activity-specific config
                if (activity.type === 'tool' && (!activity.config || !activity.config.toolName)) {
                    errors.push({
                        type: 'error',
                        field: `activities[${index}].config`,
                        message: `Tool activity ${activity.id || index} is missing toolName in config`
                    });
                }
                // Validate condition syntax
                if (activity.condition && !this.isValidCondition(activity.condition)) {
                    errors.push({
                        type: 'error',
                        field: `activities[${index}].condition`,
                        message: `Invalid condition syntax for activity ${activity.id || index}`
                    });
                }
            });
        }
        // Validate triggers
        if (!process.triggers || process.triggers.length === 0) {
            warnings.push({ type: 'warning', message: 'Process has no triggers defined' });
        }
        else {
            process.triggers.forEach((trigger, index) => {
                if (!trigger.id) {
                    errors.push({
                        type: 'error',
                        field: `triggers[${index}].id`,
                        message: `Trigger at index ${index} is missing ID`
                    });
                }
                if (!trigger.type) {
                    errors.push({
                        type: 'error',
                        field: `triggers[${index}].type`,
                        message: `Trigger ${trigger.id || index} is missing type`
                    });
                }
                if (trigger.type === 'schedule') {
                    if (!trigger.config?.cron) {
                        errors.push({
                            type: 'error',
                            field: `triggers[${index}].config.cron`,
                            message: `Schedule trigger ${trigger.id || index} is missing cron expression`
                        });
                    }
                    else if (!this.isValidCronExpression(trigger.config.cron)) {
                        errors.push({
                            type: 'error',
                            field: `triggers[${index}].config.cron`,
                            message: `Invalid cron expression for trigger ${trigger.id || index}`
                        });
                    }
                }
            });
        }
        return {
            isValid: errors.length === 0,
            errors,
            warnings
        };
    }
    isValidCondition(condition) {
        // Simple validation for condition syntax
        // Should contain comparison operators and valid syntax
        const validOperators = ['===', '!==', '==', '!=', '>', '<', '>=', '<=', '&&', '||', '!'];
        const hasValidOperator = validOperators.some(op => condition.includes(op));
        // Check for invalid characters
        const invalidChars = ['@', '#', '$'];
        const hasInvalidChars = invalidChars.some(char => condition.includes(char));
        // Check for balanced parentheses
        let parenCount = 0;
        for (const char of condition) {
            if (char === '(')
                parenCount++;
            if (char === ')')
                parenCount--;
            if (parenCount < 0)
                return false;
        }
        return hasValidOperator && !hasInvalidChars && parenCount === 0;
    }
    isValidCronExpression(cron) {
        // Basic cron expression validation
        // Format: minute hour day month weekday
        const parts = cron.trim().split(/\s+/);
        // Must have exactly 5 parts for standard cron
        if (parts.length !== 5) {
            return false;
        }
        // Validate each part
        const patterns = [
            /^(\*|[0-5]?\d)(,(\*|[0-5]?\d))*$/, // minute (0-59)
            /^(\*|[01]?\d|2[0-3])(,(\*|[01]?\d|2[0-3]))*$/, // hour (0-23)
            /^(\*|[1-9]|[12]\d|3[01])(,(\*|[1-9]|[12]\d|3[01]))*$/, // day (1-31)
            /^(\*|[1-9]|1[0-2])(,(\*|[1-9]|1[0-2]))*$/, // month (1-12)
            /^(\*|[0-6])(,(\*|[0-6]))*$/ // weekday (0-6)
        ];
        for (let i = 0; i < parts.length; i++) {
            const part = parts[i];
            // Handle ranges (e.g., 1-5)
            if (part.includes('-')) {
                const rangeParts = part.split('-');
                if (rangeParts.length !== 2)
                    return false;
                // For simplicity, just check it's not completely invalid
                if (!/^\d+$/.test(rangeParts[0]) || !/^\d+$/.test(rangeParts[1])) {
                    return false;
                }
                continue;
            }
            // Handle step values (e.g., */5)
            if (part.includes('/')) {
                const stepParts = part.split('/');
                if (stepParts.length !== 2)
                    return false;
                if (stepParts[0] !== '*' && !/^\d+$/.test(stepParts[0]))
                    return false;
                if (!/^\d+$/.test(stepParts[1]))
                    return false;
                continue;
            }
            // Validate against pattern
            if (!patterns[i].test(part)) {
                return false;
            }
        }
        return true;
    }
    async exportProcess(processId) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error(`Process ${processId} not found`);
        }
        // Create export format without runtime data
        const exportData = {
            name: process.name,
            description: process.description,
            version: process.version,
            persona: process.persona,
            triggers: process.triggers,
            activities: process.activities,
            variables: process.variables,
            exportVersion: '1.0',
            exportedAt: new Date().toISOString()
        };
        return exportData;
    }
    async importProcess(data, options) {
        let importData;
        // Handle both JSON string and object input
        if (typeof data === 'string') {
            try {
                importData = JSON.parse(data);
            }
            catch (error) {
                throw new Error('Invalid JSON format');
            }
        }
        else {
            importData = data;
        }
        // Build process from import data
        const process = {
            id: this.generateId('process'),
            name: (options?.namePrefix || '') + (importData.name || 'Imported Process'),
            description: importData.description,
            version: importData.version || '1.0.0',
            persona: importData.persona || 'custom',
            triggers: importData.triggers || [],
            activities: importData.activities || [],
            variables: importData.variables || {},
            metadata: {
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString(),
                executionCount: 0,
            }
        };
        // Save the imported process first
        await this.store.saveProcess(process);
        // Then validate it
        const validation = await this.validateProcess(process.id);
        if (!validation.isValid) {
            // Remove invalid process
            await this.store.deleteProcess(process.id);
            const errorMessages = validation.errors.map(e => e.message).join(', ');
            throw new Error(`Invalid process: ${errorMessages}`);
        }
        return process;
    }
}
//# sourceMappingURL=process-builder.js.map