/**
 * gRPC Streaming Tool Helper for Master
 *
 * Provides utilities for master tools to subscribe to worker events via gRPC
 * and display live streaming output.
 */
import { GrpcStreamingManager } from './grpc-streaming-client.js';
// Global gRPC streaming manager instance
let grpcStreamingManager = null;
function getGrpcStreamingManager() {
    if (!grpcStreamingManager) {
        grpcStreamingManager = new GrpcStreamingManager();
    }
    return grpcStreamingManager;
}
/**
 * Handle stream event and forward to onUpdate callback
 */
function handleEvent(event, onUpdate, operationId) {
    if (!onUpdate)
        return;
    const { type, ...rest } = event;
    switch (type) {
        case 'agent_message_start':
            onUpdate({
                type: 'chat_start',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                persona: rest.persona,
                operationId,
            });
            break;
        case 'agent_message_delta':
            onUpdate({
                type: 'chat_delta',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                delta: rest.delta,
                operationId,
            });
            break;
        case 'agent_message_end':
            onUpdate({
                type: 'chat_end',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                finalMessage: rest.finalMessage,
                operationId,
            });
            break;
        case 'task_started':
            onUpdate({
                type: 'task_started',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                tool: rest.tool,
                params: rest.params,
                operationId,
            });
            break;
        case 'task_progress':
            onUpdate({
                type: 'task_progress',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                progress: rest.progress,
                message: rest.message,
                operationId,
            });
            break;
        case 'tool_started':
            onUpdate({
                type: 'tool_started',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                toolName: rest.toolName,
                operationId,
            });
            break;
        case 'tool_stdout':
            onUpdate({
                type: 'tool_stdout',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                data: rest.data,
                operationId,
            });
            break;
        case 'tool_stderr':
            onUpdate({
                type: 'tool_stderr',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                data: rest.data,
                operationId,
            });
            break;
        case 'tool_finished':
            onUpdate({
                type: 'tool_finished',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                result: rest.result,
                operationId,
            });
            break;
        case 'task_completed':
            onUpdate({
                type: 'task_completed',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                result: rest.result,
                operationId,
            });
            break;
        case 'task_failed':
            onUpdate({
                type: 'task_failed',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                error: rest.error,
                operationId,
            });
            break;
        case 'task_cancelled':
            onUpdate({
                type: 'task_cancelled',
                agentId: event.agentId,
                agentName: event.agentName,
                streamKey: `${event.agentId}:${operationId}`,
                operationId,
            });
            break;
    }
}
/**
 * Subscribe to worker events via gRPC and handle streaming display
 */
export async function withGrpcWorkerStreaming(options, operation) {
    const { agentId, agentName, operationId, operationType, onUpdate, signal } = options;
    const events = [];
    const streamingManager = getGrpcStreamingManager();
    // Event handler that filters by operationId
    const eventHandler = (event) => {
        const eventOpId = event.parentOperationId;
        if (eventOpId !== operationId) {
            return;
        }
        const eventWithAgentInfo = {
            ...event,
            agentId,
            agentName,
        };
        events.push(eventWithAgentInfo);
        handleEvent(eventWithAgentInfo, onUpdate, operationId);
    };
    const client = streamingManager.subscribeToAgent(agentId, agentName, eventHandler);
    const abortHandler = () => {
        streamingManager.unsubscribeFromAgent(agentId, eventHandler);
    };
    if (signal) {
        signal.addEventListener('abort', abortHandler);
    }
    try {
        const finalResult = await operation();
        const isTerminalEvent = (event) => {
            if (operationType === 'chat') {
                return event.type === 'agent_message_end';
            }
            return event.type === 'task_completed' || event.type === 'task_failed' || event.type === 'task_cancelled';
        };
        const alreadyTerminal = events.some(isTerminalEvent);
        if (!alreadyTerminal) {
            const waitUntil = Date.now() + (operationType === 'chat' ? 30000 : 120000);
            while (Date.now() < waitUntil) {
                if (signal?.aborted) {
                    break;
                }
                if (events.some(isTerminalEvent)) {
                    break;
                }
                await new Promise(resolve => setTimeout(resolve, 100));
            }
        }
        return { finalResult, events };
    }
    finally {
        if (signal) {
            signal.removeEventListener('abort', abortHandler);
        }
        streamingManager.unsubscribeFromAgent(agentId, eventHandler);
        void client;
    }
}
/**
 * Forward a gRPC frame into the master-side streaming manager.
 */
export function forwardGrpcStreamFrame(frame) {
    const streamingManager = getGrpcStreamingManager();
    streamingManager.handleGrpcFrame(frame);
}
/**
 * Connect gRPC streaming manager to GrpcServer frame events.
 * Kept for compatibility with existing startup wiring.
 */
export function connectGrpcStreamingToServer(_onFrameCallback) {
    getGrpcStreamingManager();
    return () => {
        getGrpcStreamingManager().cleanup();
    };
}
//# sourceMappingURL=grpc-streaming-tool-helper.js.map