// engine/llm-providers/failover-chain.ts — Failover chain logic.
// SPEC-083 AC-03
import { checkProviderHealth } from './health-checker.js';
/** Maximum number of failover attempts before giving up. */
const MAX_FAILOVER_ATTEMPTS = 3;
/** In-memory log of failover events for the current session. */
const failoverLog = [];
/**
 * Walk the failover chain and return the first healthy provider that
 * has a model matching the requested quality tier.
 *
 * Returns a recommendation or null if no provider is available after
 * MAX_FAILOVER_ATTEMPTS attempts.
 */
export function resolveFailover(chain, definitions, tier, reason) {
    const defMap = new Map(definitions.map((d) => [d.id, d]));
    let previousProvider;
    let attempts = 0;
    for (const providerId of chain) {
        if (attempts >= MAX_FAILOVER_ATTEMPTS) {
            break;
        }
        const def = defMap.get(providerId);
        if (!def) {
            continue;
        }
        const health = checkProviderHealth(def, 0); // Force fresh check
        if (health.status === 'unavailable') {
            previousProvider = providerId;
            attempts++;
            continue;
        }
        const model = def.models.find((m) => m.tier === tier) ?? def.models[0];
        if (!model) {
            previousProvider = providerId;
            attempts++;
            continue;
        }
        // Log the failover event if we had to skip a previous provider
        if (previousProvider) {
            logFailoverEvent(previousProvider, providerId, reason);
        }
        return {
            providerId,
            modelId: model.id,
            tier: model.tier,
            costEstimate: { tokensEstimated: 0, usdEstimated: 0 },
            reasoning: previousProvider
                ? [`Failover from ${previousProvider}: ${reason}`]
                : ['Primary provider selected'],
            score: health.status === 'healthy' ? 1.0 : 0.5,
        };
    }
    return null;
}
/**
 * Log a failover event.
 */
function logFailoverEvent(from, to, reason) {
    failoverLog.push({
        fromProvider: from,
        toProvider: to,
        reason,
        timestamp: new Date().toISOString(),
    });
}
/**
 * Get all failover events logged in the current session.
 */
export function getFailoverLog() {
    return [...failoverLog];
}
/**
 * Clear failover log (for testing).
 */
export function clearFailoverLog() {
    failoverLog.length = 0;
}
/**
 * Build the default failover chain from provider definitions.
 * Orders by: number of models (descending), then alphabetically.
 */
export function buildDefaultChain(definitions) {
    return [...definitions]
        .sort((a, b) => b.models.length - a.models.length || a.id.localeCompare(b.id))
        .map((d) => d.id);
}
//# sourceMappingURL=failover-chain.js.map