/**
 * Simple circuit breaker for the Python sidecar.
 *
 * States: CLOSED (normal) → OPEN (fail fast) → HALF_OPEN (probe)
 * Opens after `failureThreshold` consecutive failures.
 * Resets after `resetTimeoutMs` in OPEN state.
 */

type State = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

export interface CircuitBreakerOptions {
  failureThreshold?: number;
  resetTimeoutMs?: number;
}

export class CircuitBreaker {
  private state: State = 'CLOSED';
  private failureCount = 0;
  private lastFailureTime = 0;
  private readonly failureThreshold: number;
  private readonly resetTimeoutMs: number;

  constructor(opts: CircuitBreakerOptions = {}) {
    this.failureThreshold = opts.failureThreshold ?? 5;
    this.resetTimeoutMs = opts.resetTimeoutMs ?? 30_000; // 30s
  }

  /**
   * Check if request is allowed. Throws if circuit is OPEN.
   */
  allowRequest(): boolean {
    if (this.state === 'CLOSED') return true;

    if (this.state === 'OPEN') {
      // Check if reset timeout has elapsed
      if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {
        this.state = 'HALF_OPEN';
        return true; // Allow one probe request
      }
      return false; // Still open, fail fast
    }

    // HALF_OPEN: allow the probe
    return true;
  }

  /**
   * Record a successful call — resets the breaker to CLOSED.
   */
  recordSuccess(): void {
    this.failureCount = 0;
    this.state = 'CLOSED';
  }

  /**
   * Record a failure — may trip the breaker to OPEN.
   */
  recordFailure(): void {
    this.failureCount++;
    this.lastFailureTime = Date.now();

    if (this.failureCount >= this.failureThreshold) {
      this.state = 'OPEN';
    }
  }

  get currentState(): State {
    return this.state;
  }

  get stats(): { state: State; failureCount: number; threshold: number; resetMs: number } {
    return {
      state: this.state,
      failureCount: this.failureCount,
      threshold: this.failureThreshold,
      resetMs: this.resetTimeoutMs,
    };
  }
}

// Module-level singleton for the sidecar circuit breaker
export const sidecarBreaker = new CircuitBreaker({
  failureThreshold: 5,
  resetTimeoutMs: 30_000,
});
