import { DEFAULT_PANEL_CONFIG, applyFilter, appendBounded, } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/types';
/**
 * AgentsPanel — diagnostic data provider for agent lifecycle telemetry.
 *
 * Active agents are tracked in a live map; terminal agents are moved
 * to the history buffer for filtering and display.
 */
export class AgentsPanel {
    _config;
    _eventBus;
    /** Active agents keyed by agentId. */
    _active = new Map();
    /** Completed agent history (oldest first). */
    _history = [];
    /** Registered change notification callbacks. */
    _subscribers = new Set();
    /** Unsubscribe function from the event bus. */
    _unsub = null;
    constructor(eventBus, config = DEFAULT_PANEL_CONFIG) {
        this._eventBus = eventBus;
        this._config = config;
        this._start();
    }
    _start() {
        const handler = (envelope) => {
            this._handleEnvelope(envelope);
        };
        this._unsub = this._eventBus.onDomain('agents', handler);
    }
    _handleEnvelope(envelope) {
        const p = envelope.payload;
        if (!('type' in p))
            return;
        const type = p.type;
        const traceId = envelope.traceId;
        const sessionId = envelope.sessionId;
        switch (type) {
            case 'AGENT_SPAWNING': {
                const evt = p;
                this._active.set(evt.agentId, {
                    agentId: evt.agentId,
                    taskId: evt.taskId,
                    task: evt.task,
                    state: 'spawning',
                    spawnedAt: envelope.ts,
                    traceId,
                    sessionId,
                });
                this._notify();
                break;
            }
            case 'AGENT_RUNNING': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'running';
                    record.blockedOnCallId = undefined;
                    record.blockedOnTool = undefined;
                    this._notify();
                }
                break;
            }
            case 'AGENT_AWAITING_MESSAGE': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'awaiting_message';
                    this._notify();
                }
                break;
            }
            case 'AGENT_AWAITING_TOOL': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'awaiting_tool';
                    record.blockedOnCallId = evt.callId;
                    record.blockedOnTool = evt.tool;
                    this._notify();
                }
                break;
            }
            case 'AGENT_FINALIZING': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'finalizing';
                    this._notify();
                }
                break;
            }
            case 'AGENT_COMPLETED': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'completed';
                    record.completedAt = envelope.ts;
                    record.durationMs = evt.durationMs;
                    this._finalize(record);
                }
                break;
            }
            case 'AGENT_FAILED': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'failed';
                    record.completedAt = envelope.ts;
                    record.durationMs = evt.durationMs;
                    record.error = evt.error;
                    this._finalize(record);
                }
                break;
            }
            case 'AGENT_CANCELLED': {
                const evt = p;
                const record = this._active.get(evt.agentId);
                if (record) {
                    record.state = 'cancelled';
                    record.completedAt = envelope.ts;
                    record.error = evt.reason;
                    this._finalize(record);
                }
                break;
            }
            default:
                break;
        }
    }
    _finalize(record) {
        this._active.delete(record.agentId);
        const entry = {
            agentId: record.agentId,
            taskId: record.taskId,
            task: record.task,
            state: record.state,
            spawnedAt: record.spawnedAt,
            completedAt: record.completedAt,
            durationMs: record.durationMs,
            error: record.error,
            blockedOnCallId: record.blockedOnCallId,
            blockedOnTool: record.blockedOnTool,
            traceId: record.traceId,
            sessionId: record.sessionId,
        };
        appendBounded(this._history, entry, this._config.bufferLimit);
        this._notify();
    }
    /**
     * Return a filtered snapshot combining active agents and completed history.
     * Ordered most-recent first.
     *
     * @param filter - Optional filter to restrict entries.
     */
    getSnapshot(filter) {
        const activeEntries = [];
        for (const record of this._active.values()) {
            activeEntries.push({
                agentId: record.agentId,
                taskId: record.taskId,
                task: record.task,
                state: record.state,
                spawnedAt: record.spawnedAt,
                completedAt: record.completedAt,
                durationMs: record.durationMs,
                error: record.error,
                blockedOnCallId: record.blockedOnCallId,
                blockedOnTool: record.blockedOnTool,
                traceId: record.traceId,
                sessionId: record.sessionId,
            });
        }
        const combined = [...this._history, ...activeEntries];
        return applyFilter(combined, filter, (e) => e.spawnedAt);
    }
    /**
     * Register a callback invoked whenever the data changes.
     * @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() {
        if (this._unsub) {
            this._unsub();
            this._unsub = null;
        }
        this._subscribers.clear();
    }
    _notify() {
        for (const cb of this._subscribers) {
            try {
                cb();
            }
            catch {
                // Non-fatal: subscriber errors must not crash the provider
            }
        }
    }
}
