import { evaluateResponsesHostPolicy } from '../responses-host-policy.js';
import { normalizeMessageReasoningTools } from '../../shared/reasoning-tool-normalizer.js';
import { createBridgeActionState, runBridgeActionPipeline } from '../../bridge-actions.js';
import { resolveBridgePolicy, resolvePolicyActions } from '../../bridge-policies.js';
import { consumeResponsesPayloadSnapshot, consumeResponsesPassthrough } from '../../shared/responses-reasoning-registry.js';
import { stripInternalToolingMetadata } from '../../shared/responses-tool-utils.js';
import { ProviderProtocolError } from '../../provider-protocol-error.js';
import { buildResponsesPayloadFromChatWithNative, normalizeResponsesToolCallArgumentsForClientWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
import { normalizeChatResponseReasoningToolsWithNative } from '../../../router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js';
function normalizeResponsesToolCallArgumentsForClient(responsesPayload, context) {
    const toolsRaw = Array.isArray(context?.toolsRaw) ? context?.toolsRaw : [];
    if (!toolsRaw.length) {
        return;
    }
    const normalized = normalizeResponsesToolCallArgumentsForClientWithNative(responsesPayload, toolsRaw);
    for (const key of Object.keys(responsesPayload)) {
        if (!Object.prototype.hasOwnProperty.call(normalized, key)) {
            delete responsesPayload[key];
        }
    }
    Object.assign(responsesPayload, normalized);
}
function unwrapData(value) {
    let current = value;
    const seen = new Set();
    while (current && typeof current === 'object' && !Array.isArray(current) && !seen.has(current)) {
        seen.add(current);
        if ('choices' in current || 'message' in current)
            break;
        if ('data' in current && typeof current.data === 'object') {
            current = current.data;
            continue;
        }
        break;
    }
    return current;
}
function resolveSnapshotLookupKey(response, context) {
    if (typeof response?.request_id === 'string') {
        return response.request_id;
    }
    if (typeof context?.requestId === 'string') {
        return context.requestId;
    }
    if (typeof response?.id === 'string') {
        return response.id;
    }
    return undefined;
}
function shouldStripHostManagedFields(context) {
    const result = evaluateResponsesHostPolicy(context, typeof context?.targetProtocol === 'string' ? context?.targetProtocol : undefined);
    return result.shouldStripHostManagedFields;
}
function collectRetentionContext(context) {
    const stripHostManagedFields = shouldStripHostManagedFields(context);
    return {
        metadata: context?.metadata,
        stripHostManagedFields
    };
}
function readInlineRetentionPayload(response, key) {
    const candidate = response[key];
    return candidate && typeof candidate === 'object' && !Array.isArray(candidate)
        ? candidate
        : undefined;
}
export function buildResponsesPayloadFromChat(payload, context) {
    if (!payload || typeof payload !== 'object')
        return payload;
    const response = unwrapData(payload);
    if (!response || typeof response !== 'object')
        return payload;
    if (response.object === 'response' && Array.isArray(response.output)) {
        return response;
    }
    const snapshotLookupKey = resolveSnapshotLookupKey(response, context);
    const snapshotPayload = snapshotLookupKey ? consumeResponsesPayloadSnapshot(snapshotLookupKey) : undefined;
    const passthroughPayload = snapshotLookupKey ? consumeResponsesPassthrough(snapshotLookupKey) : undefined;
    const sourceForRetention = (passthroughPayload && typeof passthroughPayload === 'object' ? passthroughPayload : undefined) ??
        readInlineRetentionPayload(response, '__responses_passthrough') ??
        (snapshotPayload && typeof snapshotPayload === 'object' ? snapshotPayload : undefined) ??
        readInlineRetentionPayload(response, '__responses_payload_snapshot');
    const retentionContext = collectRetentionContext(context);
    const hasChoicesArray = Array.isArray(response.choices);
    const choicesLength = hasChoicesArray ? response.choices.length : 0;
    if (!hasChoicesArray || choicesLength === 0) {
        const rawStatus = response.status;
        const statusCode = typeof rawStatus === 'string' && rawStatus.trim().length
            ? rawStatus.trim()
            : typeof rawStatus === 'number'
                ? String(rawStatus)
                : undefined;
        const message = typeof response.msg === 'string' && response.msg.trim().length
            ? response.msg.trim()
            : typeof response.message === 'string' && response.message.trim().length
                ? response.message.trim()
                : 'Upstream returned non-standard Chat completion payload (missing choices).';
        const mergedFallback = buildResponsesPayloadFromChatWithNative(response, {
            requestId: context?.requestId,
            toolsRaw: Array.isArray(context?.toolsRaw) ? context?.toolsRaw : [],
            metadata: retentionContext.metadata,
            stripHostManagedFields: retentionContext.stripHostManagedFields,
            sourceForRetention: sourceForRetention
        });
        if (mergedFallback.metadata) {
            stripInternalToolingMetadata(mergedFallback.metadata);
        }
        return mergedFallback;
    }
    const canonical = normalizeChatResponseReasoningToolsWithNative(response);
    const choices = Array.isArray(canonical?.choices) ? canonical.choices : [];
    const primaryChoice = choices[0] && typeof choices[0] === 'object' ? choices[0] : undefined;
    const message = primaryChoice && typeof primaryChoice.message === 'object' ? primaryChoice.message : undefined;
    if (!message) {
        throw new ProviderProtocolError('Responses bridge could not locate assistant message in Chat completion', {
            code: 'MALFORMED_RESPONSE',
            protocol: 'openai-chat',
            providerType: 'openai',
            details: {
                context: 'buildResponsesPayloadFromChat',
                choicesLength: choices.length,
                requestId: context?.requestId
            }
        });
    }
    if (message) {
        try {
            const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
            const policyActions = resolvePolicyActions(bridgePolicy, 'response_outbound');
            if (policyActions?.length) {
                const actionState = createBridgeActionState({ messages: [message] });
                runBridgeActionPipeline({
                    stage: 'response_outbound',
                    actions: policyActions,
                    protocol: bridgePolicy?.protocol ?? 'openai-responses',
                    moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
                    requestId: context?.requestId,
                    state: actionState
                });
            }
        }
        catch (error) {
            const errorMessage = error instanceof Error
                ? error.message
                : typeof error === 'string'
                    ? error
                    : 'unknown_error';
            try {
                // eslint-disable-next-line no-console
                console.error(`\x1b[31m[responses-bridge][response_outbound] bridge action pipeline failed requestId=${context?.requestId ?? 'unknown'} error=${errorMessage}\x1b[0m`);
            }
            catch {
                // ignore logging failures
            }
        }
    }
    if (message) {
        try {
            normalizeMessageReasoningTools(message, {
                idPrefix: `responses_reasoning_${context?.requestId ?? 'canonical'}`
            });
        }
        catch {
            // best-effort reasoning normalization
        }
    }
    const nativeBuilt = buildResponsesPayloadFromChatWithNative(response, {
        requestId: context?.requestId,
        toolsRaw: Array.isArray(context?.toolsRaw) ? context?.toolsRaw : [],
        metadata: retentionContext.metadata,
        stripHostManagedFields: retentionContext.stripHostManagedFields,
        sourceForRetention: sourceForRetention
    });
    const out = {
        ...nativeBuilt
    };
    normalizeResponsesToolCallArgumentsForClient(out, context);
    if (out.metadata) {
        stripInternalToolingMetadata(out.metadata);
    }
    return out;
}
export function extractRequestIdFromResponse(response) {
    if (response && typeof response === 'object' && 'metadata' in response && response.metadata && typeof response.metadata === 'object') {
        const meta = response.metadata;
        if (typeof meta.requestId === 'string')
            return meta.requestId;
    }
    return undefined;
}
