import * as store from '../storage/workflow-store.js';
export class WorkflowTriggerService {
    port;
    cronJobs = new Map();
    hookIndex = new Map();
    nodeCron = null;
    executionManager = null;
    constructor(port = 3100) {
        this.port = port;
        try {
            this.nodeCron = require('node-cron');
        }
        catch {
            // node-cron not available
        }
    }
    setExecutionManager(em) {
        this.executionManager = em;
    }
    async start() {
        const workflows = store.listWorkflows();
        for (const wf of workflows) {
            this.registerTriggers(wf);
        }
        console.log(`[TriggerService] Started. ${this.cronJobs.size} cron jobs, ${this.hookIndex.size} hooks registered`);
    }
    reloadWorkflow(workflowId) {
        this.clearTriggersForWorkflow(workflowId);
        const wf = store.getWorkflow(workflowId);
        if (wf)
            this.registerTriggers(wf);
    }
    removeWorkflow(workflowId) {
        this.clearTriggersForWorkflow(workflowId);
    }
    getHookBindings(hookName) {
        return Array.from(this.hookIndex.get(hookName) ?? []);
    }
    getHookConflicts(hookName, excludeWorkflowId) {
        const bindings = this.hookIndex.get(hookName) ?? new Set();
        const ids = Array.from(bindings)
            .map(b => b.workflowId)
            .filter(id => id !== excludeWorkflowId);
        return { conflictWorkflowIds: [...new Set(ids)] };
    }
    getHookUrl(hookName) {
        return `http://localhost:${this.port}/api/workflows/hook/${hookName}`;
    }
    validateCron(cronExpr) {
        if (!this.nodeCron)
            return { valid: false, nextRuns: [], error: 'node-cron not available' };
        if (!this.nodeCron.validate(cronExpr)) {
            return { valid: false, nextRuns: [], error: 'Invalid cron expression' };
        }
        try {
            const CronExpressionParser = require('cron-parser');
            const interval = CronExpressionParser.parse(cronExpr);
            const nextRuns = [];
            for (let i = 0; i < 5; i++) {
                const iso = interval.next().toISOString();
                if (iso)
                    nextRuns.push(iso);
            }
            return { valid: true, nextRuns };
        }
        catch (err) {
            return { valid: false, nextRuns: [], error: err.message };
        }
    }
    stop() {
        for (const [, task] of this.cronJobs) {
            task.stop();
        }
        this.cronJobs.clear();
        this.hookIndex.clear();
    }
    registerTriggers(wf) {
        if (!wf.triggers)
            return;
        for (const trigger of wf.triggers) {
            if (!trigger.enabled)
                continue;
            if (trigger.type === 'cron') {
                this.registerCronJob(wf.id, trigger);
            }
            else if (trigger.type === 'hook') {
                this.registerHookBinding(wf.id, trigger);
            }
        }
    }
    registerCronJob(workflowId, trigger) {
        if (!this.nodeCron)
            return;
        const key = `${workflowId}:${trigger.id}`;
        try {
            const task = this.nodeCron.schedule(trigger.cron, () => {
                console.log(`[TriggerService] Cron fired for workflow ${workflowId}`);
                if (this.executionManager) {
                    this.executionManager.execute({ workflowId }, '__cron__').catch((err) => {
                        console.error(`[TriggerService] Cron execution failed for ${workflowId}: ${err.message}`);
                    });
                }
            }, { timezone: trigger.timezone });
            this.cronJobs.set(key, task);
        }
        catch (err) {
            console.error(`[TriggerService] Invalid cron "${trigger.cron}" for workflow ${workflowId}: ${err.message}`);
        }
    }
    registerHookBinding(workflowId, trigger) {
        let bindings = this.hookIndex.get(trigger.hookName);
        if (!bindings) {
            bindings = new Set();
            this.hookIndex.set(trigger.hookName, bindings);
        }
        bindings.add({ workflowId, triggerId: trigger.id });
    }
    clearTriggersForWorkflow(workflowId) {
        for (const [key, task] of this.cronJobs) {
            if (key.startsWith(`${workflowId}:`)) {
                task.stop();
                this.cronJobs.delete(key);
            }
        }
        for (const [hookName, bindings] of this.hookIndex) {
            for (const binding of bindings) {
                if (binding.workflowId === workflowId) {
                    bindings.delete(binding);
                }
            }
            if (bindings.size === 0) {
                this.hookIndex.delete(hookName);
            }
        }
    }
}
//# sourceMappingURL=workflow-trigger-service.js.map