import { runStandardChatRequestFilters } from '../index.js';
import { FilterEngine, ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } from '../../filters/index.js';
import { loadFieldMapConfig } from '../../filters/utils/fieldmap-loader.js';
// processChatRequestTools/processChatResponseTools removed in favor of Filter pipeline
import { finalizeOpenAIChatResponse } from '../shared/openai-finalizer.js';
// Ported from root package (no behavior changes). Types relaxed to avoid root coupling.
export class OpenAIOpenAIConversionCodec {
    dependencies;
    id = 'openai-openai';
    initialized = false;
    ctxMap = new Map();
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    constructor(dependencies) {
        this.dependencies = dependencies;
    }
    async initialize() { this.initialized = true; }
    async convertRequest(payload, profile, context) {
        await this.ensureInit();
        const dto = {
            data: payload,
            route: {
                providerId: 'unknown',
                modelId: (payload && typeof payload === 'object' && payload.model) ? String(payload.model) : 'unknown',
                requestId: context.requestId ?? `req_${Date.now()}`,
                timestamp: Date.now()
            },
            metadata: {
                endpoint: context.endpoint ?? context.entryEndpoint,
                entryEndpoint: context.entryEndpoint,
                targetProtocol: profile.outgoingProtocol
            },
            debug: { enabled: false, stages: {} }
        };
        // Persist inbound streaming intent per requestId for response-side SSE decision
        try {
            const wantsStream = !!((dto.data && dto.data.stream === true) || (context?.stream === true) || (context?.metadata && context.metadata.stream === true));
            const ep = String(context.entryEndpoint || context.endpoint || '');
            if (dto.route.requestId)
                this.ctxMap.set(dto.route.requestId, { stream: wantsStream, entryEndpoint: ep });
        }
        catch { /* ignore */ }
        // 统一的 Chat 请求过滤链路（与 Responses/Anthropic 保持一致）
        const ctxForFilters = {
            ...context,
            requestId: dto.route.requestId,
            entryEndpoint: context.entryEndpoint ?? dto.metadata?.entryEndpoint ?? context.endpoint,
            endpoint: context.endpoint ?? dto.metadata?.endpoint
        };
        return runStandardChatRequestFilters(dto.data, profile, ctxForFilters);
    }
    async convertResponse(payload, _profile, context) {
        await this.ensureInit();
        // unwrap nested { data: {...} } wrappers until we reach an object
        const unwrap = (obj) => {
            let cur = obj;
            const guard = new Set();
            while (cur && typeof cur === 'object' && !Array.isArray(cur) && !guard.has(cur)) {
                guard.add(cur);
                if ('choices' in cur || 'id' in cur || 'object' in cur) {
                    break;
                }
                if ('data' in cur && cur.data && typeof cur.data === 'object') {
                    cur = cur.data;
                    continue;
                }
                break;
            }
            return cur;
        };
        const unwrapped = unwrap(payload);
        const dto = {
            data: unwrapped,
            metadata: {
                requestId: context.requestId ?? `req_${Date.now()}`,
                pipelineId: context.metadata?.pipelineId ?? 'conversion-router',
                processingTime: 0,
                stages: []
            }
        };
        // Run filter pipeline (no-op initially). Will be populated during migration.
        const resCtxBase = {
            requestId: context.requestId ?? dto.metadata.requestId,
            model: undefined,
            endpoint: context.entryEndpoint || context.endpoint,
            profile: 'openai-chat',
            debug: { emit: () => { } }
        };
        const engine = new FilterEngine();
        // Response-side filters (idempotent w.r.t existing logic)
        engine.registerFilter(new ResponseToolTextCanonicalizeFilter()); // response_pre
        engine.registerFilter(new ResponseToolArgumentsStringifyFilter()); // response_post
        engine.registerFilter(new ResponseFinishInvariantsFilter()); // response_post
        // Load field map config (if present) and register transforms
        try {
            const cfg = await loadFieldMapConfig('openai-openai.fieldmap.json');
            if (cfg)
                engine.setFieldMap(cfg);
            engine.registerTransform('stringifyJson', (v) => (typeof v === 'string') ? v : (() => { try {
                return JSON.stringify(v ?? {});
            }
            catch {
                return '{}';
            } })());
        }
        catch { /* ignore */ }
        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);
        // Canonicalization handled by filters (staged)
        const canonical = staged;
        // Finalize + hooks (pre/post snapshots)
        const finalized = await finalizeOpenAIChatResponse(canonical, {
            requestId: context.requestId,
            endpoint: context.entryEndpoint || context.endpoint
        });
        return finalized;
    }
    async ensureInit() { if (!this.initialized)
        await this.initialize(); }
}
