import { isRuntimeAccountMethod, isRuntimeAnonymousReadMethod, isRuntimeAppSessionBootstrapMethod, isRuntimeLocalAnonymousMethod, isRuntimeWriteMethod, RuntimeMethodIds, } from '../method-ids.js';
import { runtimeAiRequestRequiresSubject } from '../runtime-guards.js';
import { mergeRuntimeMetadata } from './metadata.js';
import { normalizeText, } from './client-validation.js';
let idempotencyCounter = 0;
function createIdempotencyKey() {
    if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
        return crypto.randomUUID();
    }
    if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
        const bytes = new Uint8Array(8);
        crypto.getRandomValues(bytes);
        const suffix = Array.from(bytes, (value) => value.toString(16).padStart(2, '0')).join('');
        return `sdk-${Date.now().toString(36)}-${suffix}`;
    }
    idempotencyCounter += 1;
    return `sdk-${Date.now().toString(36)}-${idempotencyCounter.toString(36)}`;
}
function formatAuthorizationHeader(accessToken) {
    const normalized = normalizeText(accessToken);
    if (!normalized) {
        return '';
    }
    if (normalized.toLowerCase().startsWith('bearer ')) {
        const token = normalizeText(normalized.slice(7));
        return token ? `Bearer ${token}` : '';
    }
    return `Bearer ${normalized}`;
}
async function resolveAuthorization(config, methodId, request, options) {
    if (options?.protectedAccessToken?.tokenId && options.protectedAccessToken.secret) {
        return undefined;
    }
    if (isRuntimeAnonymousReadMethod(methodId)) {
        return undefined;
    }
    if (isRuntimeLocalAnonymousMethod(methodId)) {
        return undefined;
    }
    if (isRuntimeAppSessionBootstrapMethod(methodId)) {
        return undefined;
    }
    if (isRuntimeAccountMethod(methodId)) {
        return undefined;
    }
    if ((methodId === RuntimeMethodIds.ai.executeScenario
        || methodId === RuntimeMethodIds.ai.streamScenario
        || methodId === RuntimeMethodIds.ai.submitScenarioJob)
        && !runtimeAiRequestRequiresSubject({
            request: request,
            metadata: options?.metadata,
        })) {
        return undefined;
    }
    const accessTokenInput = config.auth?.accessToken;
    if (typeof accessTokenInput === 'function') {
        const resolved = formatAuthorizationHeader(await accessTokenInput());
        return resolved || undefined;
    }
    const resolved = formatAuthorizationHeader(accessTokenInput || '');
    return resolved || undefined;
}
async function resolveProtectedAccessToken(config, options) {
    const optionTokenId = normalizeText(options?.protectedAccessToken?.tokenId);
    const optionSecret = normalizeText(options?.protectedAccessToken?.secret);
    if (optionTokenId && optionSecret) {
        return {
            tokenId: optionTokenId,
            secret: optionSecret,
        };
    }
    const authInput = config.auth?.protectedAccessToken;
    if (typeof authInput === 'function') {
        const resolved = await authInput();
        const tokenId = normalizeText(resolved?.tokenId);
        const secret = normalizeText(resolved?.secret);
        if (tokenId && secret) {
            return { tokenId, secret };
        }
        return undefined;
    }
    const tokenId = normalizeText(authInput?.tokenId);
    const secret = normalizeText(authInput?.secret);
    if (tokenId && secret) {
        return { tokenId, secret };
    }
    return undefined;
}
function runtimeMethodRequiresAppSession(methodId) {
    return methodId === RuntimeMethodIds.app.sendAppMessage
        || methodId === RuntimeMethodIds.app.subscribeAppMessages
        || methodId === RuntimeMethodIds.agent.openConversationAnchor
        || methodId === RuntimeMethodIds.agent.getConversationAnchorSnapshot
        || methodId === RuntimeMethodIds.agent.registerAvatarLiveInstanceBinding
        || methodId === RuntimeMethodIds.agent.resolveAvatarLiveInstanceBinding
        || methodId === RuntimeMethodIds.agent.getPublicChatSessionSnapshot;
}
async function resolveAppSession(config, methodId, options) {
    if (!runtimeMethodRequiresAppSession(methodId)) {
        return undefined;
    }
    const optionSessionId = normalizeText(options?.appSession?.sessionId);
    const optionSessionToken = normalizeText(options?.appSession?.sessionToken);
    if (optionSessionId && optionSessionToken) {
        return {
            sessionId: optionSessionId,
            sessionToken: optionSessionToken,
        };
    }
    const authInput = config.auth?.appSession;
    if (typeof authInput === 'function') {
        const resolved = await authInput();
        const sessionId = normalizeText(resolved?.sessionId);
        const sessionToken = normalizeText(resolved?.sessionToken);
        if (sessionId && sessionToken) {
            return { sessionId, sessionToken };
        }
        return undefined;
    }
    const sessionId = normalizeText(authInput?.sessionId);
    const sessionToken = normalizeText(authInput?.sessionToken);
    if (sessionId && sessionToken) {
        return { sessionId, sessionToken };
    }
    return undefined;
}
function withIdempotencyKey(methodId, options) {
    if (!isRuntimeWriteMethod(methodId)) {
        return options;
    }
    if (options?.idempotencyKey || options?.metadata?.idempotencyKey) {
        return options;
    }
    return {
        ...(options || {}),
        idempotencyKey: createIdempotencyKey(),
    };
}
export async function toUnaryCall(config, methodId, request, normalizedRequest, options) {
    const resolvedOptions = withIdempotencyKey(methodId, options);
    return {
        methodId,
        request,
        metadata: mergeRuntimeMetadata(config, resolvedOptions),
        authorization: await resolveAuthorization(config, methodId, normalizedRequest, resolvedOptions),
        protectedAccessToken: await resolveProtectedAccessToken(config, resolvedOptions),
        appSession: await resolveAppSession(config, methodId, resolvedOptions),
        timeoutMs: resolvedOptions?.timeoutMs,
        _responseMetadataObserver: resolvedOptions?._responseMetadataObserver,
    };
}
export async function toStreamCall(config, methodId, request, normalizedRequest, options) {
    const resolvedOptions = withIdempotencyKey(methodId, options);
    return {
        methodId,
        request,
        metadata: mergeRuntimeMetadata(config, resolvedOptions),
        authorization: await resolveAuthorization(config, methodId, normalizedRequest, resolvedOptions),
        protectedAccessToken: await resolveProtectedAccessToken(config, resolvedOptions),
        appSession: await resolveAppSession(config, methodId, resolvedOptions),
        timeoutMs: resolvedOptions?.timeoutMs,
        signal: resolvedOptions?.signal,
    };
}
//# sourceMappingURL=client-auth.js.map