import { EventEmitter } from 'events';
import { NodeCronAdapter } from './cron-adapter.js';
export class TriggerManager extends EventEmitter {
    engine;
    store;
    scheduledTriggers = new Map();
    activeTriggers = new Map();
    triggerHistory = new Map();
    isRunning = false;
    checkInterval;
    cronAdapter;
    constructor(engine, store, cronAdapter) {
        super();
        this.engine = engine;
        this.store = store;
        this.cronAdapter = cronAdapter || new NodeCronAdapter();
    }
    async initialize() {
        await this.start();
    }
    async start() {
        if (this.isRunning)
            return;
        this.isRunning = true;
        await this.loadTriggers();
        // Check for triggers every minute
        this.checkInterval = setInterval(() => {
            this.checkTriggers();
        }, 60000);
        // Initial check
        this.checkTriggers();
    }
    async stop() {
        this.isRunning = false;
        if (this.checkInterval) {
            clearInterval(this.checkInterval);
        }
        // Clear all scheduled triggers
        for (const scheduled of this.scheduledTriggers.values()) {
            if (scheduled.interval) {
                // If it's a cron task, call destroy
                if (scheduled.interval.destroy) {
                    scheduled.interval.destroy();
                }
                else {
                    clearInterval(scheduled.interval);
                }
            }
        }
        this.scheduledTriggers.clear();
    }
    async loadTriggers() {
        const processes = await this.store.getAllProcesses();
        for (const process of processes) {
            for (const trigger of process.triggers) {
                if (trigger.enabled) {
                    await this.registerTrigger(process, trigger);
                }
            }
        }
    }
    async registerTriggerInternal(process, trigger) {
        const key = `${process.id}:${trigger.id}`;
        switch (trigger.type) {
            case 'schedule':
                this.registerScheduleTrigger(process, trigger);
                break;
            case 'event':
                // Register event listeners
                this.registerEventTrigger(process, trigger);
                break;
            case 'webhook':
                // Register webhook endpoint
                this.registerWebhookTrigger(process, trigger);
                break;
            case 'condition':
                // Add to condition check list
                this.registerConditionTrigger(process, trigger);
                break;
            case 'manual':
                // No registration needed for manual triggers
                break;
        }
    }
    registerScheduleTrigger(process, trigger) {
        if (!trigger.config.cron)
            return;
        const key = `${process.id}:${trigger.id}`;
        // Simple cron parser for demo (in production use node-cron)
        const schedule = this.parseCronExpression(trigger.config.cron);
        if (schedule.interval) {
            const scheduled = {
                processId: process.id,
                triggerId: trigger.id,
                interval: setInterval(() => {
                    this.executeTrigger(process.id, trigger.id);
                }, schedule.interval),
                nextRun: schedule.nextRun
            };
            this.scheduledTriggers.set(key, scheduled);
        }
    }
    registerEventTrigger(process, trigger) {
        // In a real implementation, this would register with an event bus
        console.log(`Registered event trigger: ${trigger.config.event} for process ${process.id}`);
    }
    registerWebhookTrigger(process, trigger) {
        // In a real implementation, this would register an HTTP endpoint
        console.log(`Registered webhook trigger: ${trigger.config.endpoint} for process ${process.id}`);
    }
    registerConditionTrigger(process, trigger) {
        // Add to list of conditions to check periodically
        console.log(`Registered condition trigger for process ${process.id}`);
    }
    async checkTriggers() {
        // Check condition-based triggers
        const processes = await this.store.getAllProcesses();
        for (const process of processes) {
            for (const trigger of process.triggers) {
                if (trigger.type === 'condition' && trigger.enabled) {
                    await this.checkConditionTrigger(process, trigger);
                }
            }
        }
    }
    async checkConditionTrigger(process, trigger) {
        // Evaluate condition
        // In a real implementation, this would evaluate the condition expression
        const conditionMet = false; // Placeholder
        if (conditionMet) {
            await this.executeTrigger(process.id, trigger.id);
        }
    }
    parseCronExpression(cron) {
        // Very simplified cron parser for demo
        // In production, use a proper cron library
        const parts = cron.split(' ');
        // Handle simple cases
        if (cron === '* * * * *') {
            // Every minute
            return { interval: 60000 };
        }
        else if (cron === '0 * * * *') {
            // Every hour
            return { interval: 3600000 };
        }
        else if (cron === '0 0 * * *') {
            // Daily
            return { interval: 86400000 };
        }
        // For more complex expressions, would need proper parsing
        return {};
    }
    // Public methods for manual trigger management
    async registerTrigger(process, trigger) {
        if (!trigger.enabled)
            return;
        const key = `${process.id}:${trigger.id}`;
        this.activeTriggers.set(key, trigger);
        if (trigger.type === 'schedule' && trigger.config.cron) {
            // Use node-cron for scheduling
            if (!this.cronAdapter.validate(trigger.config.cron)) {
                throw new Error(`Invalid cron expression: ${trigger.config.cron}`);
            }
            const task = this.cronAdapter.schedule(trigger.config.cron, async () => {
                await this.executeTrigger(process.id, trigger.id);
            }, {
                scheduled: false
            });
            task.start();
            this.scheduledTriggers.set(key, {
                processId: process.id,
                triggerId: trigger.id,
                interval: task
            });
        }
    }
    async unregisterTrigger(processId, triggerId) {
        const key = `${processId}:${triggerId}`;
        this.activeTriggers.delete(key);
        const scheduled = this.scheduledTriggers.get(key);
        if (scheduled && scheduled.interval) {
            const task = scheduled.interval;
            if (task.stop)
                task.stop();
            if (task.destroy)
                task.destroy();
            this.scheduledTriggers.delete(key);
        }
    }
    getActiveTriggers(processId) {
        const triggers = [];
        for (const [key, trigger] of this.activeTriggers) {
            const [pid] = key.split(':');
            if (!processId || pid === processId) {
                triggers.push({ ...trigger, processId: pid });
            }
        }
        return triggers;
    }
    async executeTrigger(processId, triggerId, context) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error('Process not found');
        }
        const trigger = process.triggers.find(t => t.id === triggerId);
        if (!trigger) {
            throw new Error('Trigger not found');
        }
        if (!trigger.enabled) {
            throw new Error('Trigger is disabled');
        }
        const execution = await this.engine.executeProcess(process, triggerId, context);
        // Record in history
        const key = `${processId}:${triggerId}`;
        if (!this.triggerHistory.has(key)) {
            this.triggerHistory.set(key, []);
        }
        const history = this.triggerHistory.get(key);
        history.unshift({
            triggerId,
            processId,
            executionId: execution.id,
            executedAt: new Date().toISOString(),
            status: execution.status === 'completed' ? 'success' : 'failed'
        });
        // Keep only last 100 entries
        if (history.length > 100) {
            history.splice(100);
        }
        return execution;
    }
    getTriggerHistory(processId, triggerId) {
        const key = `${processId}:${triggerId}`;
        return this.triggerHistory.get(key) || [];
    }
    async updateTrigger(processId, triggerId, updates) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error('Process not found');
        }
        const trigger = process.triggers.find(t => t.id === triggerId);
        if (!trigger) {
            throw new Error('Trigger not found');
        }
        // If disabling, unregister first
        if (updates.enabled === false && trigger.enabled) {
            await this.unregisterTrigger(processId, triggerId);
        }
        // Update the trigger
        Object.assign(trigger, updates);
        // Save the updated process
        await this.store.saveProcess(process);
        // If enabling or if already enabled and config changed, re-register
        if (trigger.enabled) {
            // Unregister first to clean up old configuration
            await this.unregisterTrigger(processId, triggerId);
            // Re-register with new configuration
            await this.registerTrigger(process, trigger);
        }
    }
    async handleEvent(eventType, eventData) {
        for (const [key, trigger] of this.activeTriggers) {
            if (trigger.type === 'event' && trigger.config.event === eventType) {
                const [processId] = key.split(':');
                const process = await this.store.getProcess(processId);
                if (process) {
                    await this.executeTrigger(processId, trigger.id, {
                        event: eventType,
                        eventData
                    });
                }
            }
        }
    }
    stopAll() {
        this.stop();
        for (const scheduled of this.scheduledTriggers.values()) {
            if (scheduled.interval) {
                const task = scheduled.interval;
                if (task.stop)
                    task.stop();
                if (task.destroy)
                    task.destroy();
            }
        }
        this.scheduledTriggers.clear();
        this.activeTriggers.clear();
    }
    async triggerProcess(processId, variables) {
        const process = await this.store.getProcess(processId);
        if (!process) {
            throw new Error('Process not found');
        }
        // Find manual trigger or use first trigger
        const trigger = process.triggers.find(t => t.type === 'manual') || process.triggers[0];
        if (!trigger) {
            // Create a temporary manual trigger
            const manualTrigger = {
                id: 'manual-temp',
                type: 'manual',
                name: 'Manual Execution',
                enabled: true,
                config: {}
            };
            await this.engine.executeProcess(process, manualTrigger.id, variables);
        }
        else {
            await this.engine.executeProcess(process, trigger.id, variables);
        }
    }
    async enableTrigger(processId, triggerId) {
        const process = await this.store.getProcess(processId);
        if (!process)
            return;
        const trigger = process.triggers.find(t => t.id === triggerId);
        if (trigger && !trigger.enabled) {
            trigger.enabled = true;
            await this.store.saveProcess(process);
            await this.registerTrigger(process, trigger);
        }
    }
    async disableTrigger(processId, triggerId) {
        const process = await this.store.getProcess(processId);
        if (!process)
            return;
        const trigger = process.triggers.find(t => t.id === triggerId);
        if (trigger && trigger.enabled) {
            trigger.enabled = false;
            await this.store.saveProcess(process);
            // Remove from scheduled triggers
            const key = `${processId}:${triggerId}`;
            const scheduled = this.scheduledTriggers.get(key);
            if (scheduled && scheduled.interval) {
                clearInterval(scheduled.interval);
                this.scheduledTriggers.delete(key);
            }
        }
    }
}
//# sourceMappingURL=trigger-manager.js.map