/**
 * Runtime Events — barrel re-exports and RuntimeEventBus.
 *
 * Import from this module to access the typed event system:
 * ```ts
 * import { RuntimeEventBus, createEventEnvelope } from '../runtime/events/index.js';
 * ```
 */
import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
export { createEventEnvelope } from '@pellux/goodvibes-sdk/platform/runtime/events/envelope';
export { RUNTIME_EVENT_DOMAINS, isRuntimeEventDomain } from './domain-map.js';
export { AUTOMATION_SCHEDULE_KINDS, AUTOMATION_RUN_OUTCOMES } from '@pellux/goodvibes-sdk/platform/runtime/events/automation';
export { ROUTE_SURFACE_KINDS, ROUTE_TARGET_KINDS } from '@pellux/goodvibes-sdk/platform/runtime/events/routes';
export { CONTROL_PLANE_CLIENT_KINDS, CONTROL_PLANE_TRANSPORT_KINDS, CONTROL_PLANE_PRINCIPAL_KINDS } from '@pellux/goodvibes-sdk/platform/runtime/events/control-plane';
export { DELIVERY_KINDS } from '@pellux/goodvibes-sdk/platform/runtime/events/deliveries';
export { WATCHER_SOURCE_KINDS } from '@pellux/goodvibes-sdk/platform/runtime/events/watchers';
export { SURFACE_KINDS } from '@pellux/goodvibes-sdk/platform/runtime/events/surfaces';
/**
 * Maximum listeners per channel before a potential memory leak warning is emitted.
 *
 * 100 is a generous threshold for a single event type or domain; normal usage
 * rarely exceeds single-digit listeners. Exceeding this strongly suggests a
 * subscriber is being registered without a corresponding unsubscribe.
 */
const MAX_LISTENERS = 100;
/**
 * RuntimeEventBus — typed event bus for domain-structured runtime events.
 *
 * Supports two subscription modes:
 * - `on(eventType, callback)` — subscribe to a specific event type
 * - `onDomain(domain, callback)` — subscribe to all events in a domain
 *
 * All events are wrapped in a RuntimeEventEnvelope providing traceId,
 * sessionId, timestamps, and source context.
 *
 * This is the authoritative event transport for runtime domain signaling.
 */
export class RuntimeEventBus {
    /** Per-event-type listener sets. Keyed by the exact event type string. */
    _listeners = new Map();
    /** Per-domain listener sets. Keyed by RuntimeEventDomain. */
    _domainListeners = new Map();
    /**
     * Subscribe to a specific event type.
     *
     * @param eventType - The exact event type string to listen for.
     * @param callback - Called with the full envelope on each emission.
     * @returns An unsubscribe function.
     */
    on(eventType, callback) {
        if (!this._listeners.has(eventType)) {
            this._listeners.set(eventType, new Set());
        }
        const set = this._listeners.get(eventType);
        set.add(callback);
        if (set.size > MAX_LISTENERS) {
            logger.warn('[RuntimeEventBus] possible listener leak detected', {
                eventType,
                count: set.size,
                max: MAX_LISTENERS,
            });
        }
        return () => this._off(eventType, callback);
    }
    /**
     * Subscribe to all events in a named domain.
     *
     * @param domain - Domain name (e.g. 'turn', 'tools', 'session').
     * @param callback - Called with the full envelope for each domain event.
     * @returns An unsubscribe function.
     */
    onDomain(domain, callback) {
        if (!this._domainListeners.has(domain)) {
            this._domainListeners.set(domain, new Set());
        }
        const set = this._domainListeners.get(domain);
        set.add(callback);
        if (set.size > MAX_LISTENERS) {
            logger.warn('[RuntimeEventBus] possible domain listener leak detected', {
                domain,
                count: set.size,
                max: MAX_LISTENERS,
            });
        }
        return () => this._offDomain(domain, callback);
    }
    /**
     * Emit a runtime event envelope to all matching per-type and per-domain subscribers.
     *
     * @internal Callers MUST use the typed emitter wrapper functions from
     * `src/runtime/emitters/` rather than calling this method directly.
     * Direct usage bypasses domain-event type enforcement: TypeScript cannot
     * statically link the `domain` argument to the `envelope` payload type due
     * to union complexity limitations (TS2590), meaning mismatched pairs compile
     * without error.
     *
     * @see emitTurnSubmitted, emitToolReceived, etc. in `src/runtime/emitters/`
     *
     * @param domain - Domain this event belongs to.
     * @param envelope - The fully-formed envelope to dispatch.
     */
    emit(domain, envelope) {
        // Dispatch to per-type listeners
        const typeSet = this._listeners.get(envelope.type);
        if (typeSet) {
            for (const handler of typeSet) {
                try {
                    handler(envelope);
                }
                catch (err) {
                    logger.error('[RuntimeEventBus] listener error', {
                        eventType: envelope.type,
                        error: summarizeError(err),
                    });
                }
            }
        }
        // Dispatch to per-domain listeners
        const domainSet = this._domainListeners.get(domain);
        if (domainSet) {
            for (const handler of domainSet) {
                try {
                    handler(envelope);
                }
                catch (err) {
                    logger.error('[RuntimeEventBus] domain listener error', {
                        domain,
                        eventType: envelope.type,
                        error: summarizeError(err),
                    });
                }
            }
        }
    }
    _off(eventType, callback) {
        const set = this._listeners.get(eventType);
        set?.delete(callback);
        if (set?.size === 0)
            this._listeners.delete(eventType);
    }
    _offDomain(domain, callback) {
        const set = this._domainListeners.get(domain);
        set?.delete(callback);
        if (set?.size === 0)
            this._domainListeners.delete(domain);
    }
}
