/**
 * Task Event Bus
 *
 * Event-driven notification system for task lifecycle events.
 * Enables automatic unblocking and execution of dependent tasks
 * when their blockers complete.
 *
 * Events:
 *   task_completed  - A task finished successfully
 *   task_failed     - A task failed
 *   task_unblocked  - A task became ready (all blockers resolved)
 *   tasks_ready     - Batch notification: multiple tasks became ready
 */
/**
 * Typed event bus for task lifecycle events.
 *
 * Supports both sync and async handlers. Async handlers are
 * awaited in parallel (errors are caught and logged, not propagated).
 *
 * @example
 * ```ts
 * const bus = new TaskEventBus();
 *
 * bus.on('task_unblocked', async (event) => {
 *   if (event.type === 'task_unblocked') {
 *     console.log(`Task ${event.taskId} is now ready`);
 *     await coordinator.claim(event.taskId);
 *   }
 * });
 *
 * bus.emit({ type: 'task_completed', taskId: 'task-1' });
 * ```
 */
export class TaskEventBus {
    handlers = new Map();
    allHandlers = [];
    /**
     * Register a handler for a specific event type.
     */
    on(type, handler) {
        const list = this.handlers.get(type) || [];
        list.push(handler);
        this.handlers.set(type, list);
        // Return unsubscribe function
        return () => {
            const current = this.handlers.get(type);
            if (current) {
                const idx = current.indexOf(handler);
                if (idx >= 0)
                    current.splice(idx, 1);
            }
        };
    }
    /**
     * Register a handler for ALL event types.
     */
    onAny(handler) {
        this.allHandlers.push(handler);
        return () => {
            const idx = this.allHandlers.indexOf(handler);
            if (idx >= 0)
                this.allHandlers.splice(idx, 1);
        };
    }
    /**
     * Emit an event to all registered handlers.
     * Async handlers are awaited in parallel; errors are caught and logged.
     */
    async emit(event) {
        const typeHandlers = this.handlers.get(event.type) || [];
        const all = [...typeHandlers, ...this.allHandlers];
        if (all.length === 0)
            return;
        const results = await Promise.allSettled(all.map((h) => h(event)));
        for (const result of results) {
            if (result.status === 'rejected') {
                // Handler error is non-fatal — swallow to prevent breaking the event loop
                void result.reason;
            }
        }
    }
    /**
     * Remove all handlers (useful for testing or shutdown).
     */
    clear() {
        this.handlers.clear();
        this.allHandlers = [];
    }
    /**
     * Get count of registered handlers by type.
     */
    listenerCount(type) {
        if (type) {
            return (this.handlers.get(type)?.length || 0) + this.allHandlers.length;
        }
        let total = this.allHandlers.length;
        for (const handlers of this.handlers.values()) {
            total += handlers.length;
        }
        return total;
    }
}
// ============================================================================
// Singleton instance
// ============================================================================
let _globalBus = null;
/**
 * Get the global TaskEventBus singleton.
 * Creates one on first call.
 */
export function getTaskEventBus() {
    if (!_globalBus) {
        _globalBus = new TaskEventBus();
    }
    return _globalBus;
}
/**
 * Reset the global bus (for testing).
 */
export function resetTaskEventBus() {
    _globalBus?.clear();
    _globalBus = null;
}
//# sourceMappingURL=event-bus.js.map