import OpenAI from 'openai';
import { ProviderError } from '../types/errors.js';
import { summarizeError, toProviderError } from '../utils/error-display.js';
export function createResponsesClient(baseURL, apiKey, defaultHeaders) {
    const client = new OpenAI({
        apiKey,
        baseURL,
        ...(defaultHeaders ? { defaultHeaders } : {}),
    });
    return {
        create: (params, options) => client.responses.create(params, options),
    };
}
export function deriveNativeChatUrl(baseURL) {
    const trimmed = baseURL.replace(/\/+$/, '');
    const origin = trimmed.endsWith('/v1') ? trimmed.slice(0, -3) : trimmed;
    return `${origin}/api/v1/chat`;
}
export function toNativeChatInput(content) {
    if (!Array.isArray(content))
        return content;
    return content.map((part) => (part.type === 'text'
        ? { type: 'message', content: part.text }
        : { type: 'image', data_url: `data:${part.mediaType};base64,${part.data}` }));
}
export function buildResponsesTools(tools) {
    if (!tools || tools.length === 0)
        return undefined;
    return tools.map((tool) => ({
        type: 'function',
        name: tool.name,
        description: tool.description,
        parameters: tool.parameters,
        strict: false,
    }));
}
export function buildResponsesInput(messages) {
    const input = [];
    let assistantIndex = 0;
    for (const message of messages) {
        if (message.role === 'user') {
            if (Array.isArray(message.content)) {
                input.push({
                    role: 'user',
                    content: message.content.map((part) => (part.type === 'text'
                        ? { type: 'input_text', text: part.text }
                        : { type: 'input_image', image_url: `data:${part.mediaType};base64,${part.data}`, detail: 'auto' })),
                });
            }
            else {
                input.push({
                    role: 'user',
                    content: [{ type: 'input_text', text: message.content }],
                });
            }
            continue;
        }
        if (message.role === 'assistant') {
            if (message.content) {
                input.push({
                    type: 'message',
                    role: 'assistant',
                    content: [{ type: 'output_text', text: message.content, annotations: [] }],
                    status: 'completed',
                    id: `msg_${assistantIndex++}`,
                });
            }
            for (const toolCall of message.toolCalls ?? []) {
                input.push({
                    type: 'function_call',
                    id: `fc_${toolCall.id}`,
                    call_id: toolCall.id,
                    name: toolCall.name,
                    arguments: JSON.stringify(toolCall.arguments),
                });
            }
            continue;
        }
        input.push({
            type: 'function_call_output',
            call_id: message.callId,
            output: message.content,
        });
    }
    return input;
}
export function buildResponsesReasoning(reasoningEffort) {
    if (!reasoningEffort || reasoningEffort === 'instant')
        return undefined;
    return { effort: reasoningEffort, summary: 'auto' };
}
export function mapNativeReasoningEffort(reasoningEffort) {
    switch (reasoningEffort) {
        case 'instant':
            return 'off';
        case 'low':
        case 'medium':
        case 'high':
            return reasoningEffort;
        default:
            return undefined;
    }
}
export function extractNativeMessageText(output) {
    if (!Array.isArray(output))
        return '';
    return output
        .filter((item) => item.type === 'message')
        .map((item) => item.content ?? '')
        .join('');
}
export async function consumeSSE(body, onEvent) {
    const decoder = new TextDecoder();
    let buffer = '';
    let currentEvent = '';
    let currentData = [];
    const flush = () => {
        if (!currentEvent || currentData.length === 0) {
            currentEvent = '';
            currentData = [];
            return;
        }
        const rawPayload = currentData.join('\n').trim();
        currentEvent = currentEvent.trim();
        currentData = [];
        if (!rawPayload || rawPayload === '[DONE]') {
            currentEvent = '';
            return;
        }
        const payload = JSON.parse(rawPayload);
        const eventType = currentEvent;
        currentEvent = '';
        onEvent(eventType, payload);
    };
    const reader = body.getReader();
    while (true) {
        const { done, value } = await reader.read();
        if (done)
            break;
        if (!value)
            continue;
        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split(/\r?\n/);
        buffer = lines.pop() ?? '';
        for (const line of lines) {
            if (!line) {
                flush();
                continue;
            }
            if (line.startsWith('event:')) {
                currentEvent = line.slice('event:'.length).trim();
                continue;
            }
            if (line.startsWith('data:')) {
                currentData.push(line.slice('data:'.length).trim());
            }
        }
    }
    buffer += decoder.decode();
    if (buffer) {
        const lines = buffer.split(/\r?\n/);
        for (const line of lines) {
            if (!line) {
                flush();
                continue;
            }
            if (line.startsWith('event:')) {
                currentEvent = line.slice('event:'.length).trim();
                continue;
            }
            if (line.startsWith('data:')) {
                currentData.push(line.slice('data:'.length).trim());
            }
        }
    }
    flush();
}
export async function buildHttpError(prefix, response, provider, operation, phase) {
    const text = await response.text();
    try {
        const parsed = JSON.parse(text);
        const error = toRecord(parsed['error']);
        if (Object.keys(error).length > 0) {
            const code = typeof error['code'] === 'string' ? `${error['code']}: ` : '';
            const message = typeof error['message'] === 'string' ? error['message'] : text;
            return new ProviderError(`${prefix} error ${response.status}: ${code}${message}`, {
                statusCode: response.status,
                provider,
                operation,
                phase,
            });
        }
    }
    catch {
        // fall through to raw body
    }
    return new ProviderError(`${prefix} error ${response.status}: ${text || response.statusText}`, {
        statusCode: response.status,
        provider,
        operation,
        phase,
    });
}
export function makeTranscriptKey(model, systemPrompt, messages) {
    return stableStringify({
        model,
        ...(systemPrompt ? { systemPrompt } : {}),
        messages,
    });
}
function stableStringify(value) {
    if (value === null || typeof value !== 'object')
        return JSON.stringify(value);
    if (Array.isArray(value))
        return `[${value.map((item) => stableStringify(item)).join(',')}]`;
    const record = value;
    const keys = Object.keys(record).sort();
    return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(',')}}`;
}
export function toRecord(value) {
    return value && typeof value === 'object' ? value : {};
}
export function shouldFallbackFromNative(err) {
    const status = getErrorStatus(err);
    const message = getErrorMessage(err);
    if (status === 404 || status === 405 || status === 501)
        return true;
    if (status === 400 && /previous_response_id|response_id/i.test(message))
        return true;
    return /not implemented|unsupported|unknown endpoint/i.test(message);
}
export function shouldFallbackFromResponses(err) {
    const status = getErrorStatus(err);
    const message = getErrorMessage(err);
    if (status === 404 || status === 405 || status === 501)
        return true;
    return /not implemented|unsupported|unknown endpoint/i.test(message);
}
function getErrorStatus(err) {
    if (err && typeof err === 'object') {
        const record = err;
        if (typeof record.status === 'number')
            return record.status;
        if (typeof record.statusCode === 'number')
            return record.statusCode;
    }
    return undefined;
}
function getErrorMessage(err) {
    return summarizeError(err);
}
export function normalizeProviderError(err, provider, operation, phase = 'request') {
    const status = getErrorStatus(err);
    return toProviderError(err, {
        ...(status !== undefined ? { statusCode: status } : {}),
        provider,
        operation,
        phase,
    });
}
