import { runChatResponseToolFilters } from '../../../../../shared/tool-filter-pipeline.js';
import { buildChatResponseFromResponses } from '../../../../../shared/responses-response-utils.js';
import { normalizeAssistantTextToToolCalls } from '../../../../../shared/text-markup-normalizer.js';
import { recordStage } from '../../../stages/utils.js';
import { applyRespProcessToolGovernanceWithNative, stripOrphanFunctionCallsTagWithNative } from '../../../../../../router/virtual-router/engine-selection/native-chat-process-governance-semantics.js';
const SHELL_TOOL_NAME_ALIASES = {};
/**
 * Unified text-to-tool-calls harvest config.
 * Shared across all providers via chat process tool governance.
 */
const DEFAULT_TEXT_NORMALIZER_CONFIG = {
    jsonToolRepair: {
        toolNameAliases: SHELL_TOOL_NAME_ALIASES,
        argumentAliases: {
            exec_command: {
                cmd: ['cmd', 'command', 'input.command', 'script'],
                command: ['cmd', 'command', 'input.command', 'script'],
                workdir: ['workdir', 'cwd', 'input.cwd']
            }
        }
    }
};
function isCanonicalChatCompletion(payload) {
    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
        return false;
    }
    const obj = payload;
    const choices = Array.isArray(obj.choices) ? obj.choices : [];
    if (!choices.length)
        return false;
    const first = choices[0] && typeof choices[0] === 'object' && !Array.isArray(choices[0]) ? choices[0] : null;
    if (!first)
        return false;
    const msg = first.message;
    return Boolean(msg && typeof msg === 'object' && !Array.isArray(msg));
}
function coerceToCanonicalChatCompletion(payload) {
    if (isCanonicalChatCompletion(payload)) {
        return payload;
    }
    // ServerTool followups may re-enter via the client protocol shape (e.g. OpenAI Responses object:'response').
    // Response tool governance requires an OpenAI-chat-like surface (choices[].message) so text tool harvesting
    // and tool governance remain a single fixed path.
    try {
        const coerced = buildChatResponseFromResponses(payload);
        if (isCanonicalChatCompletion(coerced)) {
            return coerced;
        }
    }
    catch {
        // best-effort: keep original payload when bridge fails
    }
    return payload;
}
/**
 * Harvest tool calls from assistant text content when native tool_calls are missing or empty.
 * This is the single entry point for text-based tool call extraction across all providers.
 */
function harvestToolCallsFromText(payload) {
    if (!payload || typeof payload !== 'object') {
        return payload;
    }
    const choices = Array.isArray(payload.choices) ? payload.choices : [];
    if (!choices.length) {
        return payload;
    }
    let changed = false;
    for (const choice of choices) {
        if (!choice || typeof choice !== 'object' || Array.isArray(choice)) {
            continue;
        }
        const message = choice.message;
        if (!message || typeof message !== 'object' || Array.isArray(message)) {
            continue;
        }
        // Skip if already has native tool_calls
        const existingToolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : undefined;
        if (existingToolCalls && existingToolCalls.length > 0) {
            continue;
        }
        // Try to harvest from text content
        const normalized = normalizeAssistantTextToToolCalls(message, DEFAULT_TEXT_NORMALIZER_CONFIG);
        const harvestedCalls = Array.isArray(normalized.tool_calls)
            ? normalized.tool_calls
            : [];
        if (harvestedCalls.length > 0) {
            choice.message = normalized;
            changed = true;
            // Update finish_reason if needed
            const finish = typeof choice.finish_reason === 'string'
                ? String(choice.finish_reason).trim().toLowerCase()
                : '';
            if (!finish || finish === 'stop') {
                choice.finish_reason = 'tool_calls';
            }
        }
    }
    return changed ? payload : payload;
}
function sanitizeResponseShapeBeforeGovernance(payload) {
    return stripOrphanFunctionCallsTagWithNative(payload);
}
export async function runRespProcessStage1ToolGovernance(options) {
    const canonicalInput = coerceToCanonicalChatCompletion(options.payload);
    const shapeSanitizedInput = sanitizeResponseShapeBeforeGovernance(canonicalInput);
    // Single entry point for text-to-tool-calls harvest across all providers
    harvestToolCallsFromText(shapeSanitizedInput);
    recordStage(options.stageRecorder, 'chat_process.resp.stage6.canonicalize_chat_completion', {
        converted: canonicalInput !== options.payload,
        shapeSanitized: shapeSanitizedInput !== canonicalInput,
        canonicalPayload: shapeSanitizedInput
    });
    const filtered = await runChatResponseToolFilters(shapeSanitizedInput, {
        entryEndpoint: options.entryEndpoint,
        requestId: options.requestId,
        profile: 'openai-chat'
    });
    const patchedNative = applyRespProcessToolGovernanceWithNative({
        payload: filtered,
        clientProtocol: options.clientProtocol,
        entryEndpoint: options.entryEndpoint,
        requestId: options.requestId
    });
    const governed = patchedNative.governedPayload;
    recordStage(options.stageRecorder, 'chat_process.resp.stage7.tool_governance', {
        summary: patchedNative.summary,
        applied: patchedNative.summary?.applied === true,
        filteredPayload: filtered,
        governedPayload: governed
    });
    return { governedPayload: governed };
}
