import { FilterEngine } from '../../filters/index.js';
import { loadFieldMapConfig } from '../../filters/utils/fieldmap-loader.js';
import { createSnapshotWriter } from '../snapshot-utils.js';
import { normalizeChatResponseReasoningToolsWithNative as normalizeChatResponseReasoningTools } from '../../router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js';
const REQUEST_FILTER_STAGES = [
    'request_pre',
    'request_map',
    'request_post',
    'request_finalize'
];
const RESPONSE_FILTER_STAGES = [
    'response_pre',
    'response_map',
    'response_post',
    'response_finalize'
];
function assertStageCoverage(label, registeredStages, skeletonStages) {
    const allowed = new Set(skeletonStages);
    const uncovered = [];
    for (const stage of registeredStages) {
        if (!allowed.has(stage)) {
            uncovered.push(stage);
        }
    }
    if (uncovered.length) {
        throw new Error(`[tool-filter-pipeline] ${label}: registered filter stage(s) not covered by skeleton: ${uncovered.join(', ')}`);
    }
}
export async function runChatRequestToolFilters(chatRequest, options = {}) {
    const reqCtxBase = {
        requestId: options.requestId ?? `req_${Date.now()}`,
        model: typeof options.model === 'string' ? options.model : (chatRequest && typeof chatRequest === 'object' && typeof chatRequest.model === 'string' ? String(chatRequest.model) : 'unknown'),
        endpoint: options.entryEndpoint || '/v1/chat/completions',
        profile: options.profile || 'openai-chat',
        stream: options.stream === true,
        toolFilterHints: options.toolFilterHints,
        debug: { emit: () => { } }
    };
    const snapshot = createSnapshotWriter({
        requestId: reqCtxBase.requestId,
        endpoint: reqCtxBase.endpoint,
        folderHint: 'openai-chat'
    });
    const recordStage = (stage, payload) => {
        if (!snapshot)
            return;
        snapshot(stage, payload);
    };
    const preFiltered = applyLocalToolGovernance(chatRequest, options.rawPayload);
    recordStage('req_process_tool_filters_input', preFiltered);
    const engine = new FilterEngine();
    const registeredStages = new Set();
    const register = (filter) => {
        registeredStages.add(filter.stage);
        engine.registerFilter(filter);
    };
    const profile = (reqCtxBase.profile || '').toLowerCase();
    const endpoint = (reqCtxBase.endpoint || '').toLowerCase();
    const isAnthropic = profile === 'anthropic-messages' || endpoint.includes('/v1/messages');
    if (!isAnthropic) {
        try {
            const { RequestToolListFilter } = await import('../../filters/index.js');
            register(new RequestToolListFilter());
        }
        catch {
            /* optional */
        }
    }
    const { RequestToolCallsStringifyFilter, RequestToolChoicePolicyFilter } = await import('../../filters/index.js');
    register(new RequestToolCallsStringifyFilter());
    if (!isAnthropic) {
        register(new RequestToolChoicePolicyFilter());
    }
    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 */ }
    try {
        const { RequestOpenAIToolsNormalizeFilter, ToolPostConstraintsFilter } = await import('../../filters/index.js');
        register(new RequestOpenAIToolsNormalizeFilter());
        register(new ToolPostConstraintsFilter('request_finalize'));
    }
    catch {
        // optional; keep prior behavior when filter not available
    }
    assertStageCoverage('request', registeredStages, REQUEST_FILTER_STAGES);
    let staged = preFiltered;
    for (const stage of REQUEST_FILTER_STAGES) {
        staged = await engine.run(stage, staged, reqCtxBase);
        recordStage(`req_process_tool_filters_${stage}`, staged);
    }
    recordStage('req_process_tool_filters_output', staged);
    return staged;
}
function applyLocalToolGovernance(chatRequest, _rawPayload) {
    if (!chatRequest || typeof chatRequest !== 'object') {
        return chatRequest;
    }
    return chatRequest;
}
export async function runChatResponseToolFilters(chatJson, options = {}) {
    const resCtxBase = {
        requestId: options.requestId ?? `req_${Date.now()}`,
        model: undefined,
        endpoint: options.entryEndpoint || '/v1/chat/completions',
        profile: options.profile || 'openai-chat',
        debug: { emit: () => { } }
    };
    const snapshot = createSnapshotWriter({
        requestId: resCtxBase.requestId,
        endpoint: resCtxBase.endpoint,
        folderHint: 'openai-chat'
    });
    const recordStage = (stage, payload) => {
        if (!snapshot)
            return;
        snapshot(stage, payload);
    };
    recordStage('resp_process_tool_filters_input', chatJson);
    try {
        if (chatJson && typeof chatJson === 'object') {
            chatJson = normalizeChatResponseReasoningTools(chatJson, 'reasoning_choice');
        }
    }
    catch {
        // best-effort; do not block response flow on reasoning parsing issues
    }
    const engine = new FilterEngine();
    const registeredStages = new Set();
    const register = (filter) => {
        registeredStages.add(filter.stage);
        engine.registerFilter(filter);
    };
    const { ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter, ResponseToolArgumentsBlacklistFilter, ResponseToolArgumentsSchemaConvergeFilter } = await import('../../filters/index.js');
    register(new ResponseToolTextCanonicalizeFilter());
    try {
        register(new ResponseToolArgumentsSchemaConvergeFilter());
    }
    catch { /* optional */ }
    register(new ResponseToolArgumentsBlacklistFilter());
    register(new ResponseToolArgumentsStringifyFilter());
    register(new ResponseFinishInvariantsFilter());
    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 */ }
    assertStageCoverage('response', registeredStages, RESPONSE_FILTER_STAGES);
    let staged = chatJson;
    for (const stage of RESPONSE_FILTER_STAGES) {
        staged = await engine.run(stage, staged, resCtxBase);
        recordStage(`resp_process_tool_filters_${stage}`, staged);
    }
    recordStage('resp_process_tool_filters_output', staged);
    return staged;
}
