/**
 * Unified backoff policy implementation
 */

import { BackoffPolicy } from './types';
import { DEFAULT_CONFIG } from './constants';

/**
 * Calculate backoff delay with Retry-After + jittered exponential caps
 */
export function calculateBackoffDelay(
  attempt: number, 
  policy: BackoffPolicy, 
  retryAfterMs?: number
): number {
  let delay: number;
  
  // Respect Retry-After header if present and enabled
  if (policy.respectRetryAfter && retryAfterMs !== undefined) {
    delay = Math.min(retryAfterMs, policy.retryAfterMaxMs || policy.maxDelayMs);
  } else {
    // Calculate base delay based on strategy
    switch (policy.strategy) {
      case 'exponential':
        delay = policy.baseDelayMs * Math.pow(2, attempt - 1);
        break;
      case 'linear':
        delay = policy.baseDelayMs * attempt;
        break;
      case 'fixed':
        delay = policy.baseDelayMs;
        break;
      default:
        delay = policy.baseDelayMs;
    }
  }
  
  // Apply jitter if enabled
  if (policy.jitterEnabled) {
    const jitterRange = delay * policy.jitterFactor;
    const jitter = (Math.random() - 0.5) * 2 * jitterRange;
    delay = Math.max(0, delay + jitter);
  }
  
  // Cap at maximum delay
  return Math.min(delay, policy.maxDelayMs);
}

/**
 * Create default backoff policy
 */
export function createDefaultBackoffPolicy(): BackoffPolicy {
  return {
    maxAttempts: 3,
    baseDelayMs: DEFAULT_CONFIG.baseDelayMs,
    maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
    strategy: 'exponential',
    jitterEnabled: true,
    jitterFactor: DEFAULT_CONFIG.jitterFactor,
    respectRetryAfter: DEFAULT_CONFIG.respectRetryAfter,
    retryAfterMaxMs: DEFAULT_CONFIG.retryAfterMaxMs
  };
}

/**
 * Create backoff policy for rate limiting
 */
export function createRateLimitBackoffPolicy(retryAfterMs: number): BackoffPolicy {
  return {
    maxAttempts: 5,
    baseDelayMs: retryAfterMs,
    maxDelayMs: Math.max(retryAfterMs * 2, DEFAULT_CONFIG.maxDelayMs),
    strategy: 'fixed',
    jitterEnabled: true,
    jitterFactor: 0.1, // ±10% jitter for rate limits
    respectRetryAfter: true,
    retryAfterMaxMs: retryAfterMs * 2
  };
}

/**
 * Create backoff policy for network errors
 */
export function createNetworkErrorBackoffPolicy(): BackoffPolicy {
  return {
    maxAttempts: 3,
    baseDelayMs: DEFAULT_CONFIG.baseDelayMs,
    maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
    strategy: 'exponential',
    jitterEnabled: true,
    jitterFactor: DEFAULT_CONFIG.jitterFactor,
    respectRetryAfter: false
  };
}

/**
 * Create backoff policy for server errors (5xx)
 */
export function createServerErrorBackoffPolicy(): BackoffPolicy {
  return {
    maxAttempts: 3,
    baseDelayMs: 2000, // Start with 2s for server errors
    maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
    strategy: 'exponential',
    jitterEnabled: true,
    jitterFactor: 0.5, // ±50% jitter for server errors
    respectRetryAfter: false
  };
}
