/**
 * 熔断器 - 供应商级别的故障隔离
 * 
 * 状态机: CLOSED → (N次连续失败) → OPEN → (冷却期过后) → HALF_OPEN → (成功) → CLOSED
 * 
 * 使用方式:
 *   const breaker = new CircuitBreaker({ name: 'minimax', failureThreshold: 3, cooldownMs: 30000 });
 *   try {
 *     await breaker.call(async () => { ... });
 *   } catch (e) {
 *     // 熔断开启或调用失败
 *   }
 */

export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

export interface CircuitBreakerConfig {
  name: string;
  failureThreshold?: number;  // 连续失败多少次后熔断，默认 3
  cooldownMs?: number;        // 熔断冷却时间，默认 30000ms
  successThreshold?: number;  // HALF_OPEN 状态下需要连续成功多少次才恢复，默认 2
}

export class CircuitBreaker {
  readonly name: string;
  private failureThreshold: number;
  private cooldownMs: number;
  private successThreshold: number;

  private state: CircuitState = 'CLOSED';
  private failureCount = 0;
  private successCount = 0;
  private openedAt = 0;

  constructor(config: CircuitBreakerConfig) {
    this.name = config.name;
    this.failureThreshold = config.failureThreshold ?? 3;
    this.cooldownMs = config.cooldownMs ?? 30000;
    this.successThreshold = config.successThreshold ?? 2;
  }

  getState(): CircuitState {
    // 如果 OPEN 且冷却期已过，自动进入 HALF_OPEN
    if (this.state === 'OPEN' && Date.now() - this.openedAt >= this.cooldownMs) {
      this.state = 'HALF_OPEN';
      this.failureCount = 0;
      this.successCount = 0;
      console.log(`[熔断器] ${this.name}: OPEN → HALF_OPEN（冷却期已过）`);
    }
    return this.state;
  }

  isOpen(): boolean {
    return this.getState() === 'OPEN';
  }

  /**
   * 执行受保护的操作
   * 返回操作成功的结果，抛出 CircuitBreakerOpenError 或原始错误
   */
  async call<T>(fn: () => Promise<T>): Promise<T> {
    const currentState = this.getState();

    if (currentState === 'OPEN') {
      const remainingMs = this.cooldownMs - (Date.now() - this.openedAt);
      throw new CircuitBreakerOpenError(this.name, remainingMs);
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess(): void {
    if (this.state === 'HALF_OPEN') {
      this.successCount++;
      if (this.successCount >= this.successThreshold) {
        this.state = 'CLOSED';
        this.failureCount = 0;
        this.successCount = 0;
        console.log(`[熔断器] ${this.name}: HALF_OPEN → CLOSED（恢复）`);
      }
    } else {
      // CLOSED 状态，重置失败计数
      this.failureCount = 0;
    }
  }

  private onFailure(): void {
    this.failureCount++;
    this.successCount = 0;

    if (this.state === 'HALF_OPEN' || (this.state === 'CLOSED' && this.failureCount >= this.failureThreshold)) {
      this.state = 'OPEN';
      this.openedAt = Date.now();
      console.log(`[熔断器] ${this.name}: → OPEN（连续失败 ${this.failureCount} 次，冷却 ${this.cooldownMs}ms）`);
    }
  }

  /** 手动重置 */
  reset(): void {
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.successCount = 0;
    this.openedAt = 0;
  }
}

export class CircuitBreakerOpenError extends Error {
  public readonly breakerName: string;
  public readonly remainingMs: number;

  constructor(name: string, remainingMs: number) {
    super(`[${name}] 熔断器已开启，剩余冷却时间 ${Math.ceil(remainingMs / 1000)}s`);
    this.name = 'CircuitBreakerOpenError';
    this.breakerName = name;
    this.remainingMs = remainingMs;
  }
}
