import { runStandardChatRequestFilters } from '../index.js';
import { FilterEngine, ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } from '../../filters/index.js';
import { buildAnthropicFromOpenAIChat, buildOpenAIChatFromAnthropic, mapAnthropicToolsToChat, buildAnthropicToolAliasMap } from '../shared/anthropic-message-utils.js';
export { buildAnthropicFromOpenAIChat, buildOpenAIChatFromAnthropic };
export { buildAnthropicRequestFromOpenAIChat } from '../shared/anthropic-message-utils.js';
export class AnthropicOpenAIConversionCodec {
    _dependencies;
    id = 'anthropic-openai';
    initialized = false;
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    constructor(_dependencies) {
        this._dependencies = _dependencies;
    }
    async initialize() { this.initialized = true; }
    async convertRequest(payload, _profile, context) {
        if (!this.initialized) {
            await this.initialize();
        }
        const model = String(payload?.model || 'unknown');
        const { messages } = buildOpenAIChatFromAnthropic(payload, { includeToolCallIds: true });
        const out = { model, messages };
        const aliasMap = buildAnthropicToolAliasMap(payload?.tools);
        if (aliasMap) {
            context.metadata = context.metadata ?? {};
            context.metadata.anthropicToolNameMap = aliasMap;
        }
        // 最小必要的形状转换：Anthropic tools → OpenAI Chat function 工具
        try {
            const normalizedTools = mapAnthropicToolsToChat(payload?.tools);
            if (normalizedTools) {
                out.tools = normalizedTools;
            }
        }
        catch { /* keep tools undefined on failure */ }
        if (Array.isArray(payload?.stop_sequences)) {
            out.stop = payload.stop_sequences;
        }
        if (typeof payload?.temperature === 'number') {
            out.temperature = payload.temperature;
        }
        if (typeof payload?.top_p === 'number') {
            out.top_p = payload.top_p;
        }
        if (typeof payload?.max_tokens === 'number') {
            out.max_tokens = payload.max_tokens;
        }
        // 不设置默认 tool_choice；统一由 Chat 后半段治理
        // 统一流控：非流式由核心过滤器处理；此处不设置 stream
        // 统一走 Chat 请求过滤链路，使 /v1/messages 与 /v1/chat 在工具治理上保持一致
        const ctxForFilters = {
            ...context,
            requestId: context.requestId ?? `req_${Date.now()}`,
            entryEndpoint: context.entryEndpoint ?? context.endpoint,
            endpoint: context.endpoint
        };
        return runStandardChatRequestFilters(out, _profile, ctxForFilters);
    }
    async convertResponse(payload, _profile, context) {
        if (!this.initialized) {
            await this.initialize();
        }
        // 如果是 /v1/messages 且请求端声明了流式（或需要伪流式），合成 Anthropic SSE 流并透传给上层
        // 对非流式 JSON 响应，先在 OpenAI Chat canonical 上运行统一的响应工具治理，
        // 再映射回 Anthropic Messages 形状，保证与 /v1/chat 路径的行为一致。
        const dto = {
            data: payload,
            metadata: {
                requestId: context.requestId ?? `req_${Date.now()}`,
                pipelineId: context.metadata?.pipelineId ?? 'conversion-router',
                processingTime: 0,
                stages: []
            }
        };
        const resCtxBase = {
            requestId: context.requestId ?? dto.metadata.requestId,
            model: undefined,
            endpoint: context.entryEndpoint || context.endpoint,
            profile: 'openai-chat',
            debug: { emit: () => { } }
        };
        const engine = new FilterEngine();
        engine.registerFilter(new ResponseToolTextCanonicalizeFilter());
        engine.registerFilter(new ResponseToolArgumentsStringifyFilter());
        engine.registerFilter(new ResponseFinishInvariantsFilter());
        let staged = await engine.run('response_pre', dto.data, resCtxBase);
        staged = await engine.run('response_map', staged, resCtxBase);
        staged = await engine.run('response_post', staged, resCtxBase);
        const governedChat = staged;
        const aliasMap = coerceAliasMap(context.metadata?.anthropicToolNameMap);
        return buildAnthropicFromOpenAIChat(governedChat, {
            toolNameMap: aliasMap,
            requestId: context.requestId
        });
    }
}
function coerceAliasMap(candidate) {
    if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
        return undefined;
    }
    let populated = false;
    const map = {};
    for (const [key, value] of Object.entries(candidate)) {
        if (typeof key !== 'string' || typeof value !== 'string')
            continue;
        const trimmedKey = key.trim();
        if (!trimmedKey.length)
            continue;
        map[trimmedKey] = value;
        populated = true;
    }
    return populated ? map : undefined;
}
