/**
 * Sub-Agent Message Queue Service
 *
 * Buffers messages destined for sub-agents that have not yet completed
 * initialization (agentStatus !== 'active'). Messages are flushed once
 * the agent registers via the MCP `register_agent_status` tool.
 *
 * The orchestrator is excluded from this queue because it already has
 * its own deferral mechanism via QueueProcessorService.
 *
 * @module sub-agent-message-queue
 */
import { LoggerService } from '../core/logger.service.js';
import { SUB_AGENT_QUEUE_CONSTANTS } from '../../constants.js';
/**
 * Singleton service that holds pending messages per agent session.
 *
 * Messages are enqueued when a `mode: 'message'` write arrives at
 * the terminal controller for an agent that is not yet active.
 * They are dequeued and delivered sequentially when the agent
 * registers (status becomes 'active').
 */
export class SubAgentMessageQueue {
    static instance = null;
    pendingMessages = new Map();
    logger;
    constructor() {
        this.logger = LoggerService.getInstance().createComponentLogger('SubAgentMessageQueue');
    }
    /**
     * Get the singleton instance.
     *
     * @returns The SubAgentMessageQueue singleton
     */
    static getInstance() {
        if (!SubAgentMessageQueue.instance) {
            SubAgentMessageQueue.instance = new SubAgentMessageQueue();
        }
        return SubAgentMessageQueue.instance;
    }
    /**
     * Reset the singleton instance (for testing only).
     */
    static resetInstance() {
        SubAgentMessageQueue.instance = null;
    }
    /**
     * Enqueue a message for a session that is not yet active.
     * If the queue exceeds MAX_QUEUE_SIZE, the oldest message is dropped.
     *
     * @param sessionName - The target agent session name
     * @param data - The raw data string to deliver later
     */
    enqueue(sessionName, data) {
        let queue = this.pendingMessages.get(sessionName);
        if (!queue) {
            queue = [];
            this.pendingMessages.set(sessionName, queue);
        }
        // Drop oldest if at capacity
        if (queue.length >= SUB_AGENT_QUEUE_CONSTANTS.MAX_QUEUE_SIZE) {
            const dropped = queue.shift();
            this.logger.warn('Queue at capacity, dropping oldest message', {
                sessionName,
                droppedAt: dropped?.queuedAt,
                queueSize: queue.length,
            });
        }
        queue.push({
            data,
            queuedAt: Date.now(),
            sessionName,
        });
        this.logger.info('Message queued for sub-agent', {
            sessionName,
            queueSize: queue.length,
            dataLength: data.length,
        });
    }
    /**
     * Dequeue all pending messages for a session (FIFO order).
     * The queue is cleared after dequeuing.
     *
     * @param sessionName - The agent session name
     * @returns Array of queued messages in insertion order, or empty array
     */
    dequeueAll(sessionName) {
        const queue = this.pendingMessages.get(sessionName);
        if (!queue || queue.length === 0) {
            return [];
        }
        const messages = [...queue];
        this.pendingMessages.delete(sessionName);
        this.logger.info('Dequeued all messages for sub-agent', {
            sessionName,
            count: messages.length,
        });
        return messages;
    }
    /**
     * Check if there are pending messages for a session.
     *
     * @param sessionName - The agent session name
     * @returns True if there are pending messages
     */
    hasPending(sessionName) {
        const queue = this.pendingMessages.get(sessionName);
        return !!queue && queue.length > 0;
    }
    /**
     * Clear all pending messages for a session (e.g. on agent stop/exit).
     *
     * @param sessionName - The agent session name
     */
    clear(sessionName) {
        const queue = this.pendingMessages.get(sessionName);
        if (queue && queue.length > 0) {
            this.logger.info('Clearing queued messages for session', {
                sessionName,
                droppedCount: queue.length,
            });
        }
        this.pendingMessages.delete(sessionName);
    }
    /**
     * Get the number of pending messages for a session.
     *
     * @param sessionName - The agent session name
     * @returns Number of pending messages
     */
    getQueueSize(sessionName) {
        const queue = this.pendingMessages.get(sessionName);
        return queue ? queue.length : 0;
    }
}
//# sourceMappingURL=sub-agent-message-queue.service.js.map