import { DEFAULT_PANEL_CONFIG, appendBounded, } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/types';
/** All domains observed by the events panel. */
const ALL_DOMAINS = [
    'session',
    'turn',
    'tools',
    'tasks',
    'agents',
    'permissions',
    'plugins',
    'mcp',
    'transport',
    'compaction',
    'ui',
];
/**
 * Produce a condensed human-readable summary of an event payload.
 * Extracts the most diagnostic fields without exposing full payloads.
 */
function summarizePayload(type, payload) {
    if (typeof payload !== 'object' || payload === null)
        return type;
    const p = payload;
    // Extract common correlation fields for a concise summary line
    const parts = [];
    if (typeof p['tool'] === 'string')
        parts.push(`tool=${p['tool']}`);
    if (typeof p['callId'] === 'string')
        parts.push(`call=${p['callId'].slice(0, 8)}`);
    if (typeof p['agentId'] === 'string')
        parts.push(`agent=${p['agentId'].slice(0, 8)}`);
    if (typeof p['taskId'] === 'string')
        parts.push(`task=${p['taskId'].slice(0, 8)}`);
    if (typeof p['error'] === 'string')
        parts.push(`err=${p['error'].slice(0, 40)}`);
    if (typeof p['durationMs'] === 'number')
        parts.push(`${p['durationMs']}ms`);
    if (typeof p['progress'] === 'number')
        parts.push(`${p['progress']}%`);
    return parts.length > 0 ? `${type} ${parts.join(' ')}` : type;
}
/**
 * EventsPanel — diagnostic data provider for the full event timeline.
 *
 * Captures every envelope emitted across all domains, building a chronological
 * log with full tracing context. The buffer is bounded to prevent unbounded
 * memory growth in long-running sessions.
 */
export class EventsPanel {
    _config;
    _eventBus;
    /** Monotonic sequence counter for ordering within a session. */
    _seq = 0;
    /** Event history buffer (oldest first). */
    _buffer = [];
    /** Registered change notification callbacks. */
    _subscribers = new Set();
    /** Per-domain unsubscribe functions. */
    _unsubs = [];
    constructor(eventBus, config = DEFAULT_PANEL_CONFIG) {
        this._eventBus = eventBus;
        this._config = config;
        this._start();
    }
    _start() {
        for (const domain of ALL_DOMAINS) {
            const d = domain;
            const handler = (envelope) => {
                this._handleEnvelope(d, envelope);
            };
            const unsub = this._eventBus.onDomain(d, handler);
            this._unsubs.push(unsub);
        }
    }
    _handleEnvelope(domain, envelope) {
        const entry = {
            seq: this._seq++,
            type: envelope.type,
            domain,
            ts: envelope.ts,
            traceId: envelope.traceId,
            sessionId: envelope.sessionId,
            turnId: envelope.turnId,
            agentId: envelope.agentId,
            taskId: envelope.taskId,
            source: envelope.source,
            summary: summarizePayload(envelope.type, envelope.payload),
        };
        appendBounded(this._buffer, entry, this._config.bufferLimit);
        this._notify();
    }
    /**
     * Return a filtered snapshot of event timeline entries.
     * Ordered most-recent first.
     *
     * @param filter - Optional filter. Supports: domains (as `domains` strings),
     *   since/until time range, traceId/sessionId/turnId/taskId correlation,
     *   and limit.
     */
    getSnapshot(filter) {
        let result = [...this._buffer];
        if (filter) {
            if (filter.domains && filter.domains.length > 0) {
                const domainSet = new Set(filter.domains);
                result = result.filter((e) => domainSet.has(e.domain));
            }
            if (filter.traceId !== undefined) {
                result = result.filter((e) => e.traceId === filter.traceId);
            }
            if (filter.sessionId !== undefined) {
                result = result.filter((e) => e.sessionId === filter.sessionId);
            }
            if (filter.turnId !== undefined) {
                result = result.filter((e) => e.turnId === filter.turnId);
            }
            if (filter.taskId !== undefined) {
                result = result.filter((e) => e.taskId === filter.taskId);
            }
            if (filter.since !== undefined) {
                const since = filter.since;
                result = result.filter((e) => e.ts >= since);
            }
            if (filter.until !== undefined) {
                const until = filter.until;
                result = result.filter((e) => e.ts <= until);
            }
        }
        // Most recent first
        result.reverse();
        const limit = filter?.limit ?? this._config.bufferLimit;
        return result.slice(0, limit);
    }
    /**
     * Register a callback invoked whenever a new event is captured.
     * @returns An unsubscribe function.
     */
    subscribe(callback) {
        this._subscribers.add(callback);
        return () => this._subscribers.delete(callback);
    }
    /**
     * Release all event bus subscriptions and clear internal state.
     */
    dispose() {
        for (const unsub of this._unsubs) {
            unsub();
        }
        this._unsubs.length = 0;
        this._subscribers.clear();
    }
    _notify() {
        for (const cb of this._subscribers) {
            try {
                cb();
            }
            catch {
                // Non-fatal: subscriber errors must not crash the provider
            }
        }
    }
}
