import { extractOutputSegments } from './output-content-normalizer.js';
import { createBridgeActionState, runBridgeActionPipeline } from '../bridge-actions.js';
import { resolveBridgePolicy, resolvePolicyActions } from '../bridge-policies.js';
import { registerResponsesPayloadSnapshot, registerResponsesPassthrough } from './responses-reasoning-registry.js';
import { normalizeFunctionCallIdWithNative, sanitizeReasoningTaggedTextWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
import { sanitizeResponsesFunctionNameWithNative } from '../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
function selectCallId(entry) {
    const candidates = [
        entry?.call_id,
        entry?.tool_call_id,
        entry?.tool_use_id,
        entry?.id
    ];
    for (const candidate of candidates) {
        if (typeof candidate === 'string' && candidate.trim().length > 0) {
            return candidate.trim();
        }
    }
    return undefined;
}
function normalizeToolCall(entry, fallbackPrefix) {
    if (!entry || typeof entry !== 'object')
        return null;
    const fn = entry.function || {};
    const rawName = sanitizeResponsesFunctionNameWithNative(fn.name ?? entry.name);
    if (!rawName)
        return null;
    const argsRaw = fn.arguments ?? entry.arguments ?? {};
    const argsStr = typeof argsRaw === 'string'
        ? argsRaw
        : (() => {
            try {
                return JSON.stringify(argsRaw ?? {});
            }
            catch {
                return '{}';
            }
        })();
    const callIdRaw = selectCallId(entry);
    const callId = typeof callIdRaw === 'string' && callIdRaw.length
        ? callIdRaw
        : normalizeFunctionCallIdWithNative({
            callId: callIdRaw,
            fallback: `${fallbackPrefix}_${Math.random().toString(36).slice(2, 10)}`
        });
    return {
        id: callId,
        type: 'function',
        function: {
            name: rawName,
            arguments: argsStr
        }
    };
}
export function collectToolCallsFromResponses(response) {
    const collected = [];
    const seenIds = new Set();
    const pushCall = (call, source) => {
        if (!call)
            return;
        const key = typeof call.id === 'string' ? call.id : `${source}_${collected.length}`;
        if (key && seenIds.has(key))
            return;
        if (key)
            seenIds.add(key);
        collected.push(call);
    };
    const required = response?.required_action?.submit_tool_outputs?.tool_calls;
    if (Array.isArray(required)) {
        for (const call of required) {
            pushCall(normalizeToolCall(call, 'req_call'), 'req_call');
        }
    }
    const outputItems = Array.isArray(response.output) ? response.output : [];
    for (const item of outputItems) {
        if (!item || typeof item !== 'object')
            continue;
        const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
        if (type !== 'function_call')
            continue;
        pushCall(normalizeToolCall(item, 'output_call'), 'output_call');
    }
    return collected;
}
export function resolveFinishReason(response, toolCalls) {
    const meta = response.metadata && typeof response.metadata === 'object'
        ? response.metadata
        : undefined;
    if (meta && typeof meta.finish_reason === 'string') {
        return meta.finish_reason;
    }
    if (toolCalls.length > 0) {
        return 'tool_calls';
    }
    const status = typeof response.status === 'string' ? response.status.toLowerCase() : '';
    if (status === 'requires_action')
        return 'tool_calls';
    if (status === 'in_progress' || status === 'streaming')
        return 'length';
    if (status === 'cancelled')
        return 'cancelled';
    if (status === 'failed')
        return 'error';
    return 'stop';
}
function unwrapResponsesResponse(payload) {
    if (!payload || typeof payload !== 'object')
        return undefined;
    if (typeof payload.object === 'string' && payload.object === 'response') {
        return payload;
    }
    if (Array.isArray(payload.output) ||
        typeof payload.status === 'string' ||
        payload.required_action) {
        return payload;
    }
    let current = payload;
    const visited = new Set();
    while (current && typeof current === 'object' && !Array.isArray(current)) {
        if (visited.has(current))
            break;
        visited.add(current);
        if (typeof current.object === 'string' && current.object === 'response') {
            return current;
        }
        if (current.response && typeof current.response === 'object') {
            current = current.response;
            continue;
        }
        if (current.data && typeof current.data === 'object') {
            current = current.data;
            continue;
        }
        break;
    }
    return undefined;
}
function collectRawReasoningSegments(response) {
    const segments = [];
    const outputItems = Array.isArray(response.output) ? response.output : [];
    for (const item of outputItems) {
        if (!item || typeof item !== 'object')
            continue;
        const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
        if (type !== 'reasoning')
            continue;
        const content = Array.isArray(item.content) ? item.content : [];
        for (const part of content) {
            if (part && typeof part === 'object' && typeof part.text === 'string') {
                segments.push(part.text);
            }
        }
    }
    return segments;
}
function collectReasoningSummarySegments(response) {
    const segments = [];
    const outputItems = Array.isArray(response.output) ? response.output : [];
    for (const item of outputItems) {
        if (!item || typeof item !== 'object')
            continue;
        const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
        if (type !== 'reasoning')
            continue;
        const summary = Array.isArray(item.summary) ? item.summary : [];
        for (const entry of summary) {
            if (typeof entry === 'string') {
                segments.push(entry);
                continue;
            }
            if (entry && typeof entry === 'object' && typeof entry.text === 'string') {
                segments.push(entry.text);
            }
        }
    }
    return segments;
}
function collectReasoningEncryptedContent(response) {
    const outputItems = Array.isArray(response.output) ? response.output : [];
    for (const item of outputItems) {
        if (!item || typeof item !== 'object')
            continue;
        const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
        if (type !== 'reasoning')
            continue;
        const encrypted = item.encrypted_content;
        if (typeof encrypted === 'string' && encrypted.trim().length) {
            return encrypted;
        }
    }
    return undefined;
}
function buildReasoningPayload(options) {
    const { summarySegments, contentSegments, encryptedContent } = options;
    const summary = summarySegments.length
        ? summarySegments.map((text) => ({ type: 'summary_text', text }))
        : undefined;
    const content = contentSegments.length
        ? contentSegments.map((text) => ({ type: 'reasoning_text', text }))
        : undefined;
    if (!summary && !content && encryptedContent === undefined) {
        return undefined;
    }
    return {
        summary,
        content,
        encrypted_content: encryptedContent
    };
}
function registerPassthroughSnapshot(payload) {
    const ids = new Set();
    const requestId = typeof payload?.request_id === 'string' ? payload.request_id.trim() : '';
    const id = typeof payload?.id === 'string' ? payload.id.trim() : '';
    if (requestId.length)
        ids.add(requestId);
    if (id.length)
        ids.add(id);
    for (const candidate of ids) {
        registerResponsesPassthrough(candidate, payload);
    }
}
function cloneSnapshot(value) {
    try {
        const structuredCloneImpl = globalThis.structuredClone;
        if (typeof structuredCloneImpl === 'function') {
            return structuredCloneImpl(value);
        }
    }
    catch {
        /* ignore structuredClone failures */
    }
    try {
        return JSON.parse(JSON.stringify(value));
    }
    catch {
        return { ...value };
    }
}
export function buildChatResponseFromResponses(payload) {
    if (!payload || typeof payload !== 'object')
        return payload;
    const response = unwrapResponsesResponse(payload);
    if (!response) {
        if (Array.isArray(payload.choices)) {
            registerPassthroughSnapshot(payload);
            return payload;
        }
        return payload;
    }
    const id = typeof response.id === 'string' ? response.id : `resp_${Date.now()}`;
    const model = response.model;
    const created = typeof response.created_at === 'number'
        ? response.created_at
        : (response.created ?? Math.floor(Date.now() / 1000));
    const usage = response.usage;
    const toolCalls = collectToolCallsFromResponses(response);
    const { textParts, reasoningParts } = extractOutputSegments(response);
    const rawReasoningSegments = collectRawReasoningSegments(response);
    const summaryReasoningSegments = collectReasoningSummarySegments(response);
    const encryptedReasoning = collectReasoningEncryptedContent(response);
    const outputTextRaw = typeof response.output_text === 'string' && response.output_text.trim().length
        ? response.output_text
        : undefined;
    const explicitOutput = typeof outputTextRaw === 'string'
        ? sanitizeReasoningTaggedTextWithNative(outputTextRaw)
        : undefined;
    const messageContentText = explicitOutput || textParts.join('\n').trim();
    const messageContent = messageContentText || '';
    const message = {
        role: 'assistant',
        content: messageContent
    };
    try {
        const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
        const policyActions = resolvePolicyActions(bridgePolicy, 'response_inbound');
        if (policyActions?.length) {
            const actionState = createBridgeActionState({
                messages: [message],
                rawResponse: response
            });
            runBridgeActionPipeline({
                stage: 'response_inbound',
                actions: policyActions,
                protocol: bridgePolicy?.protocol ?? 'openai-responses',
                moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
                requestId: typeof response?.id === 'string' ? response.id : undefined,
                state: actionState
            });
        }
    }
    catch {
        // Ignore policy errors
    }
    if (toolCalls.length) {
        message.tool_calls = toolCalls;
    }
    const reasoningSegments = rawReasoningSegments.length
        ? rawReasoningSegments
        : (reasoningParts.length ? reasoningParts : summaryReasoningSegments);
    if (reasoningSegments.length) {
        message.reasoning_content = reasoningSegments.join('\n');
    }
    const finishReason = resolveFinishReason(response, toolCalls);
    const chat = {
        id,
        object: 'chat.completion',
        created,
        model,
        choices: [
            {
                index: 0,
                finish_reason: finishReason,
                message
            }
        ]
    };
    const hasOutputTextField = Object.prototype.hasOwnProperty.call(response, 'output_text');
    const reasoningPayload = buildReasoningPayload({
        summarySegments: summaryReasoningSegments,
        contentSegments: rawReasoningSegments.length ? rawReasoningSegments : reasoningParts,
        encryptedContent: encryptedReasoning
    });
    if (reasoningPayload) {
        chat.__responses_reasoning = reasoningPayload;
    }
    chat.__responses_output_text_meta = {
        hasField: hasOutputTextField,
        value: typeof outputTextRaw === 'string'
            ? sanitizeReasoningTaggedTextWithNative(outputTextRaw)
            : undefined
    };
    if (usage !== undefined) {
        chat.usage = usage;
    }
    const requestId = typeof response.request_id === 'string'
        ? response.request_id
        : (typeof response.id === 'string' ? response.id : undefined);
    if (requestId) {
        chat.request_id = requestId;
    }
    registerResponsesPayloadSnapshot(id, response);
    if (requestId && requestId !== id) {
        registerResponsesPayloadSnapshot(requestId, response);
    }
    const snapshot = cloneSnapshot(response);
    if (snapshot) {
        chat.__responses_payload_snapshot = snapshot;
    }
    return chat;
}
