import { registerServerToolHandler } from '../registry.js';
import { isCompactionRequest } from './compaction-detect.js';
import { extractCapturedChatSeed } from './followup-request-builder.js';
import { ensureRuntimeMetadata, readRuntimeMetadata } from '../../conversion/runtime-metadata.js';
const FLOW_ID = 'empty_reply_continue';
const MAX_TOOL_HINTS = 24;
const handler = async (ctx) => {
    if (!ctx.capabilities.reenterPipeline) {
        return null;
    }
    // 避免在 followup 请求里再次触发，防止循环。
    const rt = readRuntimeMetadata(ctx.adapterContext);
    const followupRaw = rt?.serverToolFollowup;
    if (followupRaw === true || (typeof followupRaw === 'string' && followupRaw.trim().toLowerCase() === 'true')) {
        return null;
    }
    if (hasCompactionFlag(rt)) {
        return null;
    }
    // 通用空回复续跑：只要是 /v1/responses 链路且满足空回复判定，不区分 provider family / protocol。
    const entryEndpoint = (ctx.entryEndpoint || '').toLowerCase();
    if (!entryEndpoint.includes('/v1/responses')) {
        return null;
    }
    // 支持两种客户端协议形状：
    // - OpenAI Chat: choices[0].message.content
    // - OpenAI Responses: output/output_text/status
    const base = ctx.base;
    const emptyDecision = decideEmptyReply(base);
    if (!emptyDecision.shouldTrigger) {
        return null;
    }
    // 统计连续空回复次数，超过上限后不再自动续写，而是返回一个可重试错误。
    const previousCountRaw = rt?.emptyReplyContinueCount ?? rt?.geminiEmptyReplyCount;
    const previousCount = typeof previousCountRaw === 'number' && Number.isFinite(previousCountRaw) && previousCountRaw >= 0
        ? previousCountRaw
        : 0;
    const nextCount = previousCount + 1;
    const captured = getCapturedRequest(ctx.adapterContext);
    if (!captured) {
        return null;
    }
    if (isCompactionRequest(captured)) {
        return null;
    }
    const seed = extractCapturedChatSeed(captured);
    if (!seed) {
        return null;
    }
    const continueText = buildContinueUserText(seed);
    // 超过最多 3 次空回复：返回一个 HTTP_HANDLER_ERROR 形状的错误，交由上层错误中心处理。
    if (nextCount > 3) {
        const errorChat = {
            id: base.id,
            object: base.object,
            model: base.model,
            error: {
                message: 'fetch failed: empty_reply_continue exceeded max empty replies',
                code: 'HTTP_HANDLER_ERROR',
                type: 'servertool_empty_reply'
            }
        };
        return {
            flowId: FLOW_ID,
            finalize: async () => ({
                chatResponse: errorChat,
                execution: {
                    flowId: FLOW_ID
                }
            })
        };
    }
    return {
        flowId: FLOW_ID,
        finalize: async () => ({
            chatResponse: ctx.base,
            execution: {
                flowId: FLOW_ID,
                followup: {
                    requestIdSuffix: ':continue',
                    entryEndpoint: ctx.entryEndpoint,
                    injection: {
                        ops: [
                            { op: 'preserve_tools' },
                            { op: 'append_assistant_message', required: false },
                            { op: 'append_user_text', text: continueText }
                        ]
                    },
                    metadata: (() => {
                        const meta = {};
                        const runtime = ensureRuntimeMetadata(meta);
                        runtime.emptyReplyContinueCount = nextCount;
                        // Backward compatibility for old snapshots/guards.
                        runtime.geminiEmptyReplyCount = nextCount;
                        return meta;
                    })()
                }
            }
        })
    };
};
registerServerToolHandler('empty_reply_continue', handler, { trigger: 'auto', hook: { phase: 'default', priority: 20 } });
function decideEmptyReply(base) {
    // 1) OpenAI Chat shape
    const choices = Array.isArray(base.choices) ? base.choices : [];
    if (choices.length > 0) {
        const firstRaw = choices[0];
        if (!firstRaw || typeof firstRaw !== 'object') {
            return { shouldTrigger: false };
        }
        const first = firstRaw;
        const finishReasonRaw = typeof first.finish_reason === 'string' && first.finish_reason.trim()
            ? first.finish_reason.trim()
            : '';
        const finishReason = finishReasonRaw.toLowerCase();
        const isStop = finishReason === 'stop';
        const isMaxTokens = finishReason === 'length'; // 映射自 Gemini 的 MAX_TOKENS
        if (!isStop && !isMaxTokens) {
            return { shouldTrigger: false };
        }
        const message = first.message && typeof first.message === 'object' && !Array.isArray(first.message)
            ? first.message
            : null;
        if (!message) {
            return { shouldTrigger: false };
        }
        const contentRaw = message.content;
        const contentText = typeof contentRaw === 'string' ? contentRaw.trim() : '';
        // 对于 finish_reason=stop，仅在真正“空回复”时触发；
        // 对于 finish_reason=length（MAX_TOKENS 截断），允许已有内容，视为需要自动续写。
        if (isStop && contentText.length > 0) {
            return { shouldTrigger: false };
        }
        const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
        if (toolCalls.length > 0) {
            return { shouldTrigger: false };
        }
        return { shouldTrigger: true };
    }
    // 2) OpenAI Responses shape
    const statusRaw = typeof base.status === 'string' ? base.status.trim().toLowerCase() : '';
    if (statusRaw && statusRaw !== 'completed') {
        return { shouldTrigger: false };
    }
    if (base.required_action && typeof base.required_action === 'object') {
        return { shouldTrigger: false };
    }
    const outputText = extractResponsesOutputText(base);
    if (outputText.length > 0) {
        return { shouldTrigger: false };
    }
    const outputRaw = Array.isArray(base.output) ? base.output : [];
    if (outputRaw.some((item) => hasToolLikeOutput(item))) {
        return { shouldTrigger: false };
    }
    // 允许 output 为空或仅包含空消息：视作空回复，触发自动续写。
    return { shouldTrigger: true };
}
function extractResponsesOutputText(base) {
    const raw = base.output_text;
    if (typeof raw === 'string') {
        return raw.trim();
    }
    if (Array.isArray(raw)) {
        const texts = raw
            .map((entry) => (typeof entry === 'string' ? entry : ''))
            .filter((entry) => entry.trim().length > 0);
        if (texts.length > 0) {
            return texts.join('\n').trim();
        }
    }
    const output = Array.isArray(base.output) ? (base.output) : [];
    const chunks = [];
    for (const item of output) {
        if (!item || typeof item !== 'object' || Array.isArray(item))
            continue;
        if (typeof item.type !== 'string')
            continue;
        const type = String(item.type).trim().toLowerCase();
        if (type !== 'message')
            continue;
        const content = Array.isArray(item.content) ? (item.content) : [];
        for (const part of content) {
            if (!part || typeof part !== 'object' || Array.isArray(part))
                continue;
            const pType = typeof part.type === 'string'
                ? String(part.type).trim().toLowerCase()
                : '';
            if (pType === 'output_text' || pType === 'text' || pType === 'input_text') {
                const text = typeof part.text === 'string' ? String(part.text) : '';
                if (text.trim().length)
                    chunks.push(text.trim());
                continue;
            }
            const fallback = typeof part.content === 'string'
                ? String(part.content).trim()
                : '';
            if (fallback.length)
                chunks.push(fallback);
        }
    }
    return chunks.join('\n').trim();
}
function hasToolLikeOutput(value) {
    if (!value || typeof value !== 'object' || Array.isArray(value)) {
        return false;
    }
    const typeRaw = value.type;
    const type = typeof typeRaw === 'string' ? typeRaw.trim().toLowerCase() : '';
    if (!type) {
        return false;
    }
    return (type === 'tool_call' ||
        type === 'tool_use' ||
        type === 'function_call' ||
        type.includes('tool'));
}
function getCapturedRequest(adapterContext) {
    if (!adapterContext || typeof adapterContext !== 'object') {
        return null;
    }
    const captured = adapterContext.capturedChatRequest;
    if (!captured || typeof captured !== 'object' || Array.isArray(captured)) {
        return null;
    }
    return captured;
}
function hasCompactionFlag(rt) {
    const flag = rt && typeof rt === 'object' && !Array.isArray(rt) ? rt.compactionRequest : undefined;
    if (flag === true) {
        return true;
    }
    if (typeof flag === 'string' && flag.trim().toLowerCase() === 'true') {
        return true;
    }
    return false;
}
function buildContinueUserText(seed) {
    const toolNames = collectToolNames(seed);
    if (!toolNames.length) {
        return '继续执行';
    }
    const shown = toolNames.slice(0, MAX_TOOL_HINTS);
    const omitted = toolNames.length - shown.length;
    const listText = shown.join(', ');
    const tail = omitted > 0 ? `（其余 ${omitted} 个省略）` : '';
    return `继续执行。可用工具列表：${listText}${tail}。请优先调用这些工具，不要返回空回复。`;
}
function collectToolNames(seed) {
    const tools = Array.isArray(seed.tools) ? seed.tools : [];
    if (!tools.length) {
        return [];
    }
    const names = [];
    const seen = new Set();
    for (const tool of tools) {
        if (!tool || typeof tool !== 'object' || Array.isArray(tool))
            continue;
        const fnNode = tool.function;
        const fnName = fnNode && typeof fnNode === 'object' && !Array.isArray(fnNode)
            ? normalizeToolName(fnNode.name)
            : '';
        const fallbackName = normalizeToolName(tool.name);
        const resolvedName = fnName || fallbackName;
        if (!resolvedName || seen.has(resolvedName))
            continue;
        seen.add(resolvedName);
        names.push(resolvedName);
    }
    return names;
}
function normalizeToolName(value) {
    return typeof value === 'string' && value.trim().length > 0 ? value.trim() : '';
}
