const DEFAULT_CONFIG = {
    failureThreshold: 3,
    cooldownMs: 30_000,
    fatalCooldownMs: 120_000
};
export class ProviderHealthManager {
    states = new Map();
    config = DEFAULT_CONFIG;
    configure(config) {
        if (config) {
            const normalizedCooldown = Math.max(5_000, config.cooldownMs ?? DEFAULT_CONFIG.cooldownMs);
            const fatalCooldownCandidate = config.fatalCooldownMs ?? DEFAULT_CONFIG.fatalCooldownMs ?? normalizedCooldown;
            this.config = {
                failureThreshold: Math.max(1, config.failureThreshold ?? DEFAULT_CONFIG.failureThreshold),
                cooldownMs: normalizedCooldown,
                fatalCooldownMs: Math.max(fatalCooldownCandidate, normalizedCooldown)
            };
        }
    }
    registerProviders(providerKeys) {
        for (const key of providerKeys) {
            if (!this.states.has(key)) {
                this.states.set(key, {
                    providerKey: key,
                    state: 'healthy',
                    failureCount: 0
                });
            }
        }
    }
    recordFailure(providerKey, reason) {
        const state = this.getState(providerKey);
        state.failureCount += 1;
        state.lastFailureAt = Date.now();
        if (reason) {
            state.reason = reason;
        }
        // 在新版策略中，普通失败仅用于监控；不再根据 failureThreshold 自动熔断。
        // 只有显式 fatal 或 tripProvider 调用时才会进入 tripped 状态。
        return state;
    }
    /**
     * 为可恢复错误（例如 429）提供短暂冷静期：在 cooldownMs 内将 providerKey
     * 视为不可用，但不使用 fatalCooldownMs 的长熔断时间。
     */
    cooldownProvider(providerKey, reason, overrideMs) {
        const state = this.getState(providerKey);
        state.failureCount += 1;
        state.state = 'tripped';
        state.reason = reason;
        const ttl = overrideMs ?? this.config.cooldownMs;
        state.cooldownExpiresAt = Date.now() + ttl;
        state.lastFailureAt = Date.now();
        return state;
    }
    recordSuccess(providerKey) {
        const state = this.getState(providerKey);
        state.failureCount = 0;
        state.state = 'healthy';
        state.cooldownExpiresAt = undefined;
        state.lastFailureAt = undefined;
        state.reason = undefined;
        return state;
    }
    tripProvider(providerKey, reason, cooldownOverrideMs) {
        const state = this.getState(providerKey);
        state.failureCount = Math.max(state.failureCount, this.config.failureThreshold);
        state.state = 'tripped';
        state.reason = reason;
        const ttl = cooldownOverrideMs ?? this.config.fatalCooldownMs ?? this.config.cooldownMs;
        state.cooldownExpiresAt = Date.now() + ttl;
        state.lastFailureAt = Date.now();
        return state;
    }
    isAvailable(providerKey) {
        const state = this.getState(providerKey);
        if (state.state === 'healthy') {
            return true;
        }
        if (state.cooldownExpiresAt && Date.now() >= state.cooldownExpiresAt) {
            this.recordSuccess(providerKey);
            return true;
        }
        return false;
    }
    getSnapshot() {
        return Array.from(this.states.values()).map((state) => ({
            providerKey: state.providerKey,
            state: state.state,
            failureCount: state.failureCount,
            cooldownExpiresAt: state.cooldownExpiresAt
        }));
    }
    getConfig() {
        return { ...this.config };
    }
    getState(providerKey) {
        if (!this.states.has(providerKey)) {
            this.states.set(providerKey, {
                providerKey,
                state: 'healthy',
                failureCount: 0
            });
        }
        return this.states.get(providerKey);
    }
}
