import { failNativeRequired, isNativeDisabledByEnv } from './native-router-hotpath-policy.js';
import { loadNativeRouterHotpathBindingForInternalUse } from './native-router-hotpath.js';
function readNativeFunction(name) {
    const binding = loadNativeRouterHotpathBindingForInternalUse();
    const fn = binding?.[name];
    return typeof fn === 'function' ? fn : null;
}
function safeStringify(value) {
    try {
        return JSON.stringify(value);
    }
    catch {
        return undefined;
    }
}
function parseActionDescriptor(candidate) {
    if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
        return null;
    }
    const row = candidate;
    const name = typeof row.name === 'string' ? row.name.trim() : '';
    if (!name) {
        return null;
    }
    const options = row.options;
    return {
        name,
        ...(options && typeof options === 'object' && !Array.isArray(options)
            ? { options: options }
            : {})
    };
}
function parseActionDescriptors(raw) {
    try {
        const parsed = JSON.parse(raw);
        if (parsed == null) {
            return undefined;
        }
        if (!Array.isArray(parsed)) {
            return null;
        }
        const out = parsed
            .map((entry) => parseActionDescriptor(entry))
            .filter((entry) => Boolean(entry));
        return out;
    }
    catch {
        return null;
    }
}
function parsePhase(candidate) {
    if (candidate == null) {
        return undefined;
    }
    if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
        return null;
    }
    const row = candidate;
    const out = {};
    if (Object.prototype.hasOwnProperty.call(row, 'inbound')) {
        if (row.inbound == null) {
            out.inbound = undefined;
        }
        else if (Array.isArray(row.inbound)) {
            const inbound = row.inbound
                .map((entry) => parseActionDescriptor(entry))
                .filter((entry) => Boolean(entry));
            out.inbound = inbound;
        }
        else {
            return null;
        }
    }
    if (Object.prototype.hasOwnProperty.call(row, 'outbound')) {
        if (row.outbound == null) {
            out.outbound = undefined;
        }
        else if (Array.isArray(row.outbound)) {
            const outbound = row.outbound
                .map((entry) => parseActionDescriptor(entry))
                .filter((entry) => Boolean(entry));
            out.outbound = outbound;
        }
        else {
            return null;
        }
    }
    return out;
}
function parsePolicy(raw) {
    try {
        const parsed = JSON.parse(raw);
        if (parsed == null) {
            return undefined;
        }
        if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
            return null;
        }
        const row = parsed;
        const id = typeof row.id === 'string' ? row.id.trim() : '';
        if (!id) {
            return null;
        }
        const protocol = typeof row.protocol === 'string' && row.protocol.trim().length
            ? row.protocol.trim()
            : undefined;
        const moduleType = typeof row.moduleType === 'string' && row.moduleType.trim().length
            ? row.moduleType.trim()
            : undefined;
        const request = parsePhase(row.request);
        if (request === null) {
            return null;
        }
        const response = parsePhase(row.response);
        if (response === null) {
            return null;
        }
        return {
            id,
            ...(protocol ? { protocol } : {}),
            ...(moduleType ? { moduleType } : {}),
            ...(request ? { request } : {}),
            ...(response ? { response } : {})
        };
    }
    catch {
        return null;
    }
}
export function resolveBridgePolicyWithNative(options) {
    const capability = 'resolveBridgePolicyJson';
    const fail = (reason) => failNativeRequired(capability, reason);
    if (isNativeDisabledByEnv()) {
        return fail('native disabled');
    }
    const fn = readNativeFunction(capability);
    if (!fn) {
        return fail();
    }
    const payloadJson = safeStringify({
        protocol: options?.protocol,
        moduleType: options?.moduleType
    });
    if (!payloadJson) {
        return fail('json stringify failed');
    }
    try {
        const raw = fn(payloadJson);
        if (typeof raw !== 'string' || !raw) {
            return fail('empty result');
        }
        const parsed = parsePolicy(raw);
        return parsed === null ? fail('invalid payload') : parsed;
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
        return fail(reason);
    }
}
export function resolveBridgePolicyActionsWithNative(policy, stage) {
    const capability = 'resolveBridgePolicyActionsJson';
    const fail = (reason) => failNativeRequired(capability, reason);
    if (isNativeDisabledByEnv()) {
        return fail('native disabled');
    }
    const fn = readNativeFunction(capability);
    if (!fn) {
        return fail();
    }
    const policyJson = safeStringify(policy ?? null);
    if (!policyJson) {
        return fail('json stringify failed');
    }
    try {
        const raw = fn(policyJson, String(stage || ''));
        if (typeof raw !== 'string' || !raw) {
            return fail('empty result');
        }
        const parsed = parseActionDescriptors(raw);
        return parsed === null ? fail('invalid payload') : parsed;
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
        return fail(reason);
    }
}
function parseLayoutRule(candidate) {
    if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
        return null;
    }
    const row = candidate;
    const code = typeof row.code === 'string' ? row.code.trim() : '';
    const path = typeof row.path === 'string' ? row.path.trim() : '';
    const detail = typeof row.detail === 'string' ? row.detail : '';
    if (code !== 'forbid_wrapper' || !path || !detail) {
        return null;
    }
    return { code: 'forbid_wrapper', path, detail };
}
function parseFlattenRule(candidate) {
    if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
        return null;
    }
    const row = candidate;
    const wrapperKey = typeof row.wrapperKey === 'string' ? row.wrapperKey.trim() : '';
    if (!wrapperKey) {
        return null;
    }
    const allowKeys = Array.isArray(row.allowKeys)
        ? row.allowKeys.filter((entry) => typeof entry === 'string')
        : undefined;
    const aliasKeys = row.aliasKeys && typeof row.aliasKeys === 'object' && !Array.isArray(row.aliasKeys)
        ? Object.fromEntries(Object.entries(row.aliasKeys).filter((entry) => typeof entry[1] === 'string'))
        : undefined;
    const onlyIfTargetMissing = typeof row.onlyIfTargetMissing === 'boolean' ? row.onlyIfTargetMissing : undefined;
    return {
        wrapperKey,
        ...(allowKeys ? { allowKeys } : {}),
        ...(aliasKeys ? { aliasKeys } : {}),
        ...(typeof onlyIfTargetMissing === 'boolean' ? { onlyIfTargetMissing } : {})
    };
}
function parseProtocolSpec(raw) {
    try {
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
            return null;
        }
        const row = parsed;
        const id = row.id;
        if (id !== 'openai-chat' &&
            id !== 'openai-responses' &&
            id !== 'anthropic-messages' &&
            id !== 'gemini-chat') {
            return null;
        }
        const providerOutbound = row.providerOutbound && typeof row.providerOutbound === 'object' && !Array.isArray(row.providerOutbound)
            ? row.providerOutbound
            : null;
        if (!providerOutbound) {
            return null;
        }
        const enforceEnabled = providerOutbound.enforceEnabled;
        if (typeof enforceEnabled !== 'boolean') {
            return null;
        }
        const allowedTopLevelKeys = Array.isArray(providerOutbound.allowedTopLevelKeys)
            ? providerOutbound.allowedTopLevelKeys.filter((entry) => typeof entry === 'string')
            : undefined;
        const enforceAllowedTopLevelKeys = typeof providerOutbound.enforceAllowedTopLevelKeys === 'boolean'
            ? providerOutbound.enforceAllowedTopLevelKeys
            : undefined;
        const reservedKeyPrefixes = Array.isArray(providerOutbound.reservedKeyPrefixes)
            ? providerOutbound.reservedKeyPrefixes.filter((entry) => typeof entry === 'string')
            : [];
        const forbidWrappers = Array.isArray(providerOutbound.forbidWrappers)
            ? providerOutbound.forbidWrappers
                .map((entry) => parseLayoutRule(entry))
                .filter((entry) => Boolean(entry))
            : [];
        const flattenWrappers = Array.isArray(providerOutbound.flattenWrappers)
            ? providerOutbound.flattenWrappers
                .map((entry) => parseFlattenRule(entry))
                .filter((entry) => Boolean(entry))
            : [];
        const toolSurface = row.toolSurface && typeof row.toolSurface === 'object' && !Array.isArray(row.toolSurface)
            ? row.toolSurface
            : null;
        if (!toolSurface) {
            return null;
        }
        const expectedToolFormat = toolSurface.expectedToolFormat;
        if (expectedToolFormat !== 'openai' &&
            expectedToolFormat !== 'anthropic' &&
            expectedToolFormat !== 'gemini') {
            return null;
        }
        const expectedHistoryCarrier = toolSurface.expectedHistoryCarrier === 'messages' || toolSurface.expectedHistoryCarrier === 'input'
            ? toolSurface.expectedHistoryCarrier
            : undefined;
        return {
            id,
            providerOutbound: {
                enforceEnabled,
                ...(allowedTopLevelKeys ? { allowedTopLevelKeys } : {}),
                ...(typeof enforceAllowedTopLevelKeys === 'boolean' ? { enforceAllowedTopLevelKeys } : {}),
                reservedKeyPrefixes,
                forbidWrappers,
                flattenWrappers
            },
            toolSurface: {
                expectedToolFormat,
                ...(expectedHistoryCarrier ? { expectedHistoryCarrier } : {})
            }
        };
    }
    catch {
        return null;
    }
}
function parseStringArrayValue(value) {
    if (!Array.isArray(value)) {
        return null;
    }
    const out = value.filter((entry) => typeof entry === 'string');
    return out;
}
function parseHubProtocolAllowlists(raw) {
    try {
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
            return null;
        }
        const row = parsed;
        const openaiChatAllowedFields = parseStringArrayValue(row.openaiChatAllowedFields);
        const openaiChatParametersWrapperAllowKeys = parseStringArrayValue(row.openaiChatParametersWrapperAllowKeys);
        const openaiResponsesAllowedFields = parseStringArrayValue(row.openaiResponsesAllowedFields);
        const openaiResponsesParametersWrapperAllowKeys = parseStringArrayValue(row.openaiResponsesParametersWrapperAllowKeys);
        const anthropicAllowedFields = parseStringArrayValue(row.anthropicAllowedFields);
        const anthropicParametersWrapperAllowKeys = parseStringArrayValue(row.anthropicParametersWrapperAllowKeys);
        const geminiAllowedFields = parseStringArrayValue(row.geminiAllowedFields);
        if (!openaiChatAllowedFields ||
            !openaiChatParametersWrapperAllowKeys ||
            !openaiResponsesAllowedFields ||
            !openaiResponsesParametersWrapperAllowKeys ||
            !anthropicAllowedFields ||
            !anthropicParametersWrapperAllowKeys ||
            !geminiAllowedFields) {
            return null;
        }
        return {
            openaiChatAllowedFields,
            openaiChatParametersWrapperAllowKeys,
            openaiResponsesAllowedFields,
            openaiResponsesParametersWrapperAllowKeys,
            anthropicAllowedFields,
            anthropicParametersWrapperAllowKeys,
            geminiAllowedFields
        };
    }
    catch {
        return null;
    }
}
export function resolveHubProtocolSpecWithNative(input) {
    const capability = 'resolveHubProtocolSpecJson';
    const fail = (reason) => failNativeRequired(capability, reason);
    if (isNativeDisabledByEnv()) {
        return fail('native disabled');
    }
    const fn = readNativeFunction(capability);
    if (!fn) {
        return fail();
    }
    const payloadJson = safeStringify({
        protocol: input?.protocol,
        allowlists: {
            openaiChatAllowedFields: input?.allowlists?.openaiChatAllowedFields ?? [],
            openaiChatParametersWrapperAllowKeys: input?.allowlists?.openaiChatParametersWrapperAllowKeys ?? [],
            openaiResponsesAllowedFields: input?.allowlists?.openaiResponsesAllowedFields ?? [],
            openaiResponsesParametersWrapperAllowKeys: input?.allowlists?.openaiResponsesParametersWrapperAllowKeys ?? [],
            anthropicAllowedFields: input?.allowlists?.anthropicAllowedFields ?? [],
            anthropicParametersWrapperAllowKeys: input?.allowlists?.anthropicParametersWrapperAllowKeys ?? [],
            geminiAllowedFields: input?.allowlists?.geminiAllowedFields ?? []
        }
    });
    if (!payloadJson) {
        return fail('json stringify failed');
    }
    try {
        const raw = fn(payloadJson);
        if (typeof raw !== 'string' || !raw) {
            return fail('empty result');
        }
        const parsed = parseProtocolSpec(raw);
        return parsed ?? fail('invalid payload');
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
        return fail(reason);
    }
}
export function resolveHubProtocolAllowlistsWithNative() {
    const capability = 'resolveHubProtocolAllowlistsJson';
    const fail = (reason) => failNativeRequired(capability, reason);
    if (isNativeDisabledByEnv()) {
        return fail('native disabled');
    }
    const fn = readNativeFunction(capability);
    if (!fn) {
        return fail();
    }
    try {
        const raw = fn();
        if (typeof raw !== 'string' || !raw) {
            return fail('empty result');
        }
        const parsed = parseHubProtocolAllowlists(raw);
        return parsed ?? fail('invalid payload');
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
        return fail(reason);
    }
}
