/**
 * Request Runner
 * 
 * Executes HTTP requests via backend proxy to bypass CORS
 * and ensure auth headers are sent properly.
 * Supports streaming responses for SSE endpoints.
 */ import { buildRequest } from './request-builder';
/**
 * Executes a REST request via the backend proxy
 */ export async function executeRequest(request, options = {}) {
    try {
        // Build the request
        const builtRequest = buildRequest(request, options);
        // Send request through our backend proxy
        const proxyResponse = await fetch('/api/proxy', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                url: builtRequest.url,
                method: builtRequest.method,
                headers: builtRequest.headers,
                requestBody: builtRequest.body instanceof FormData ? undefined // FormData not supported through JSON proxy
                 : builtRequest.body
            }),
            signal: options.signal
        });
        if (!proxyResponse.ok) {
            const errorData = await proxyResponse.json().catch(()=>({}));
            return {
                status: proxyResponse.status,
                statusText: proxyResponse.statusText,
                headers: {},
                body: JSON.stringify(errorData),
                responseTime: 0,
                size: 0,
                error: errorData.error || 'Proxy request failed'
            };
        }
        const result = await proxyResponse.json();
        return {
            status: result.status,
            statusText: result.statusText,
            headers: result.headers || {},
            body: result.body,
            responseTime: result.responseTime || 0,
            size: result.size || 0,
            error: result.error
        };
    } catch (error) {
        if (error instanceof Error && error.name === 'AbortError') {
            throw new Error('Request cancelled');
        }
        return {
            status: 0,
            statusText: 'Error',
            headers: {},
            body: null,
            responseTime: 0,
            size: 0,
            error: error instanceof Error ? error.message : 'Unknown error'
        };
    }
}
/**
 * Executes a streaming request (for SSE endpoints)
 * Falls back to regular request if the endpoint isn't actually SSE
 */ export async function executeStreamingRequest(request, options = {}) {
    const startTime = Date.now();
    try {
        const builtRequest = buildRequest(request, options);
        // Use streaming proxy
        const response = await fetch('/api/proxy-stream', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                url: builtRequest.url,
                method: builtRequest.method,
                headers: builtRequest.headers,
                requestBody: builtRequest.body instanceof FormData ? undefined : builtRequest.body
            }),
            signal: options.signal
        });
        if (!response.ok) {
            const errorData = await response.json().catch(()=>({}));
            return {
                status: response.status,
                statusText: response.statusText,
                headers: {},
                body: JSON.stringify(errorData),
                responseTime: Date.now() - startTime,
                size: 0,
                error: errorData.error || 'Proxy request failed'
            };
        }
        const contentType = response.headers.get('content-type') || '';
        // Check if streaming response (our proxy wraps SSE responses as SSE)
        const isProxyStreaming = contentType.includes('text/event-stream');
        if (isProxyStreaming && response.body) {
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            let accumulated = '';
            let metadata = null;
            let totalSize = 0;
            let buffer = '';
            try {
                while(true){
                    const { done, value } = await reader.read();
                    if (done) break;
                    buffer += decoder.decode(value, {
                        stream: true
                    });
                    // Process complete SSE events (ending with \n\n)
                    const events = buffer.split('\n\n');
                    buffer = events.pop() || ''; // Keep incomplete event in buffer
                    for (const eventStr of events){
                        const lines = eventStr.split('\n');
                        for (const line of lines){
                            if (line.startsWith('data: ')) {
                                try {
                                    const event = JSON.parse(line.slice(6));
                                    if (event.type === 'metadata') {
                                        metadata = {
                                            status: event.status,
                                            statusText: event.statusText,
                                            headers: event.headers
                                        };
                                        options.onStreamStart?.(metadata);
                                    } else if (event.type === 'chunk') {
                                        // Accumulate raw SSE data - formatting happens in response viewer
                                        accumulated += event.data;
                                        totalSize += event.size || 0;
                                        options.onChunk?.(event.data, accumulated);
                                    } else if (event.type === 'done') {
                                        totalSize = event.totalSize || totalSize;
                                    } else if (event.type === 'error') {
                                        return {
                                            status: metadata?.status || 0,
                                            statusText: metadata?.statusText || 'Error',
                                            headers: metadata?.headers || {},
                                            body: accumulated,
                                            responseTime: Date.now() - startTime,
                                            size: totalSize,
                                            error: event.error,
                                            isStreaming: true
                                        };
                                    }
                                } catch  {
                                // Ignore parse errors for partial data
                                }
                            }
                        }
                    }
                }
            } catch (readError) {
                // Handle read errors gracefully
                if (readError instanceof Error && readError.name === 'AbortError') {
                    throw readError;
                }
            }
            return {
                status: metadata?.status || 200,
                statusText: metadata?.statusText || 'OK',
                headers: metadata?.headers || {},
                body: accumulated,
                responseTime: Date.now() - startTime,
                size: totalSize,
                isStreaming: true
            };
        }
        // Non-streaming response from streaming proxy (endpoint wasn't SSE)
        const result = await response.json();
        return {
            status: result.status,
            statusText: result.statusText,
            headers: result.headers || {},
            body: result.body,
            responseTime: Date.now() - startTime,
            size: result.size || 0,
            error: result.error,
            isStreaming: false
        };
    } catch (error) {
        if (error instanceof Error && error.name === 'AbortError') {
            throw new Error('Request cancelled');
        }
        return {
            status: 0,
            statusText: 'Error',
            headers: {},
            body: null,
            responseTime: Date.now() - startTime,
            size: 0,
            error: error instanceof Error ? error.message : 'Unknown error'
        };
    }
}
/**
 * Creates a cancelable request execution
 */ export function createCancelableRequest(request, options = {}) {
    const abortController = new AbortController();
    return {
        execute: ()=>executeRequest(request, {
                ...options,
                signal: abortController.signal
            }),
        cancel: ()=>abortController.abort()
    };
}
/**
 * Creates a cancelable streaming request execution
 */ export function createCancelableStreamingRequest(request, options = {}) {
    const abortController = new AbortController();
    return {
        execute: ()=>executeStreamingRequest(request, {
                ...options,
                signal: abortController.signal
            }),
        cancel: ()=>abortController.abort()
    };
}
