/**
 * Retry backoff strategies
 */

import type { TBackoffStrategy } from '../webrequest.types.js';

export interface IBackoffCalculator {
  calculate(attempt: number, initialDelay: number, maxDelay: number): number;
}

/**
 * Exponential backoff strategy
 * Delay increases exponentially: initialDelay * 2^attempt
 */
export class ExponentialBackoff implements IBackoffCalculator {
  calculate(attempt: number, initialDelay: number, maxDelay: number): number {
    const delay = initialDelay * Math.pow(2, attempt - 1);
    return Math.min(delay, maxDelay);
  }
}

/**
 * Linear backoff strategy
 * Delay increases linearly: initialDelay * attempt
 */
export class LinearBackoff implements IBackoffCalculator {
  calculate(attempt: number, initialDelay: number, maxDelay: number): number {
    const delay = initialDelay * attempt;
    return Math.min(delay, maxDelay);
  }
}

/**
 * Constant backoff strategy
 * Delay stays constant: initialDelay
 */
export class ConstantBackoff implements IBackoffCalculator {
  calculate(attempt: number, initialDelay: number, maxDelay: number): number {
    return Math.min(initialDelay, maxDelay);
  }
}

/**
 * Get backoff calculator for a given strategy
 */
export function getBackoffCalculator(
  strategy: TBackoffStrategy,
): IBackoffCalculator {
  switch (strategy) {
    case 'exponential':
      return new ExponentialBackoff();
    case 'linear':
      return new LinearBackoff();
    case 'constant':
      return new ConstantBackoff();
    default:
      return new ExponentialBackoff();
  }
}

/**
 * Add jitter to delay to prevent thundering herd
 */
export function addJitter(delay: number, jitterFactor: number = 0.1): number {
  const jitter = delay * jitterFactor * Math.random();
  return delay + jitter;
}
