"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MissingCredentialError = void 0;
exports.resolveCredential = resolveCredential;
const oauth_1 = require("../oauth");
const logger_1 = require("../../lib/logger");
/**
 * Thrown when credential resolution finds no credential for a provider.
 * Caught by route handlers to return structured 422 responses.
 */
class MissingCredentialError extends Error {
    constructor(provider) {
        super(`No credential found for provider "${provider}". Register one at Credentials.`);
        this.name = 'MissingCredentialError';
        this.provider = provider;
    }
}
exports.MissingCredentialError = MissingCredentialError;
/** Well-known provider → env var mappings. */
const SYSTEM_ENV_VARS = {
    anthropic: ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN'],
    openai: ['OPENAI_API_KEY'],
};
/**
 * Resolve the best credential for a principal + provider.
 *
 * Four-tier cascade:
 * 1. Primary principal's stored OAuth token / API key
 * 2. Fallback principal's stored credential (when provided — e.g., the human
 *    invoker in a bot-executed workflow)
 * 3. System env var (e.g., ANTHROPIC_API_KEY)
 * 4. null (caller typically throws MissingCredentialError)
 *
 * @param principal - The authenticated principal (user or bot)
 * @param provider - OAuth provider name (e.g., 'anthropic', 'openai')
 * @param label - Optional credential label for multi-credential accounts
 * @param options - Optional fallback principal for dual-identity resolution
 * @returns Resolved credential or null if none available
 */
async function resolveCredential(principal, provider, label, options) {
    // 1. Try primary principal's stored credential
    try {
        const decrypted = await (0, oauth_1.getFreshAccessToken)(principal.id, provider, label);
        if (decrypted) {
            return {
                value: decrypted.accessToken,
                source: principal.type,
                type: 'oauth_token',
            };
        }
    }
    catch (err) {
        logger_1.loggerRegistry.debug(`No stored credential for principal=${principal.id} provider=${provider}: ${err}`);
    }
    // 2. Try fallback principal's credential (dual-identity: bot runs, user's token needed)
    if (options?.fallbackPrincipal) {
        try {
            const decrypted = await (0, oauth_1.getFreshAccessToken)(options.fallbackPrincipal.id, provider, label);
            if (decrypted) {
                return {
                    value: decrypted.accessToken,
                    source: options.fallbackPrincipal.type,
                    type: 'oauth_token',
                };
            }
        }
        catch (err) {
            logger_1.loggerRegistry.debug(`No stored credential for fallback principal=${options.fallbackPrincipal.id} provider=${provider}: ${err}`);
        }
    }
    // 3. System env var fallback
    const envVars = SYSTEM_ENV_VARS[provider];
    if (envVars) {
        for (const varName of envVars) {
            const value = process.env[varName];
            if (value) {
                return {
                    value,
                    source: 'system',
                    type: 'api_key',
                };
            }
        }
    }
    return null;
}
