/**
 * Foliko Retry Strategy - 重试策略系统
 * 提供多种重试策略，支持指数退避、抖动等
 */

const { logger } = require('./logger');

const log = logger.child('RetryStrategy');

/**
 * 重试策略配置
 * @typedef {Object} RetryConfig
 * @property {number} maxAttempts - 最大重试次数
 * @property {number} baseDelay - 基础延迟（毫秒）
 * @property {number} maxDelay - 最大延迟（毫秒）
 * @property {number} [factor=2] - 退避因子
 * @property {number} [jitter=0.1] - 抖动因子（0-1）
 * @property {Function} [shouldRetry] - 判断是否应重试的函数
 * @property {Function} [onRetry] - 重试前回调
 */

/**
 * 预设的重试策略
 */
const PRESETS = {
  /** 快速重试（适合网络瞬时抖动） */
  fast: {
    maxAttempts: 3,
    baseDelay: 100,
    maxDelay: 1000,
    factor: 2,
    jitter: 0.1,
  },
  /** 标准重试（适合大多数场景） */
  standard: {
    maxAttempts: 3,
    baseDelay: 1000,
    maxDelay: 10000,
    factor: 2,
    jitter: 0.2,
  },
  /** 保守重试（适合外部依赖） */
  conservative: {
    maxAttempts: 5,
    baseDelay: 2000,
    maxDelay: 30000,
    factor: 2,
    jitter: 0.3,
  },
  /** 指数退避（适合限流场景） */
  exponential: {
    maxAttempts: 5,
    baseDelay: 1000,
    maxDelay: 60000,
    factor: 2,
    jitter: 0.1,
  },
  /** 激进重试（适合紧急恢复，快速多次尝试） */
  aggressive: {
    maxAttempts: 5,
    baseDelay: 200,
    maxDelay: 2000,
    factor: 1.5,
    jitter: 0.05,
  },
  /** 空闲连接保活（适合长时间运行的连接检查） */
  idle: {
    maxAttempts: 3,
    baseDelay: 5000,
    maxDelay: 15000,
    factor: 1.5,
    jitter: 0.1,
    shouldRetry: (error) => {
      const networkCodes = ['ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND'];
      return error.code && networkCodes.includes(error.code);
    },
  },
  /** 数据库重试（适合数据库连接） */
  database: {
    maxAttempts: 5,
    baseDelay: 1000,
    maxDelay: 30000,
    factor: 2,
    jitter: 0.2,
    shouldRetry: (error) => {
      const dbCodes = [
        'ECONNREFUSED',
        'ECONNRESET',
        'ETIMEDOUT',
        'PROTOCOL_CONNECTION_LOST',
        'ER_CON_COUNT_ERROR',
      ];
      const dbKeywords = [
        'connection',
        'timeout',
        'database',
        'sql',
        'mysql',
        'postgres',
        'mongodb',
      ];
      if (error.code && dbCodes.includes(error.code)) return true;
      const msg = (error.message || '').toLowerCase();
      return dbKeywords.some((k) => msg.includes(k));
    },
  },
  /** API调用重试（适合第三方API） */
  api: {
    maxAttempts: 4,
    baseDelay: 500,
    maxDelay: 8000,
    factor: 2,
    jitter: 0.15,
    shouldRetry: (error) => {
      const status = error.status || error.statusCode;
      if (status && (status >= 500 || status === 429)) return true;
      const networkCodes = ['ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND'];
      if (error.code && networkCodes.includes(error.code)) return true;
      return false;
    },
  },
};
