/**
 * CircuitBreaker 熔断器
 * 用于防止工具调用失败时持续重试导致资源耗尽
 */

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

/**
 * 熔断器状态
 */
const CircuitState = {
  CLOSED: 'closed', // 正常状态，允许请求通过
  OPEN: 'open', // 熔断状态，拒绝请求
  HALF_OPEN: 'half_open', // 半开状态，允许一个测试请求
};

/**
 * 熔断器选项
 * @typedef {Object} CircuitBreakerOptions
 * @property {number} [failureThreshold=3] - 连续失败次数达到此值时触发熔断
 * @property {number} [successThreshold=2] - 半开状态下连续成功次数达到此值时关闭熔断
 * @property {number} [timeout=60000] - 熔断持续时间（毫秒），超时后进入半开状态
 * @property {string} [name] - 熔断器名称（用于日志）
 */

/**
 * CircuitBreaker 熔断器类
 * 使用滑动窗口记录请求成功/失败，帮助防止持续失败的工具调用
 */
class CircuitBreaker {
  /**
   * @param {CircuitBreakerOptions} options
   */
  constructor(options = {}) {
    this.options = {
      failureThreshold: options.failureThreshold || 3,
      successThreshold: options.successThreshold || 2,
      timeout: options.timeout || 60000, // 默认 1 分钟
      name: options.name || 'default',
    };

    this._state = CircuitState.CLOSED;
    this._failureCount = 0;
    this._successCount = 0;
    this._lastFailureTime = null;
    this._halfOpenAttempts = 0;

    this._log = logger.child('CircuitBreaker', { name: this.options.name });
  }

  /**
   * 获取当前状态
   * @returns {string}
   */
  getState() {
    // 检查是否需要从 OPEN 转为 HALF_OPEN
    if (this._state === CircuitState.OPEN && this._lastFailureTime) {
      const elapsed = Date.now() - this._lastFailureTime;
      if (elapsed >= this.options.timeout) {
        this._transitionTo(CircuitState.HALF_OPEN);
      }
    }
    return this._state;
  }

  /**
   * 检查是否允许执行
   * @returns {boolean}
   */
  canExecute() {
    const state = this.getState();
    return state === CircuitState.CLOSED || state === CircuitState.HALF_OPEN;
  }

  /**
   * 执行带熔断保护的函数
   * @param {Function} fn - 要执行的异步函数
   * @returns {Promise<any>}
   * @throws {Error} 如果熔断器处于 OPEN 状态，抛出错误
   */
  async execute(fn) {
    if (!this.canExecute()) {
      throw new Error(
        `Circuit breaker is OPEN for '${this.options.name}'. ` +
          `Tool calls are temporarily blocked. Try again later.`
      );
    }

    try {
      const result = await fn();
      this._onSuccess();
      return result;
    } catch (err) {
      this._onFailure(err);
      throw err;
    }
  }

  /**
   * 记录成功
   * @private
   */
  _onSuccess() {
    if (this._state === CircuitState.HALF_OPEN) {
      this._successCount++;
      this._halfOpenAttempts++;
      this._log.debug(`Half-open success: ${this._successCount}/${this.options.successThreshold}`);

      if (this._successCount >= this.options.successThreshold) {
        this._transitionTo(CircuitState.CLOSED);
      }
    } else if (this._state === CircuitState.CLOSED) {
      // 成功后重置失败计数
      this._failureCount = 0;
    }
  }

  /**
   * 记录失败
   * @param {Error} err
   * @private
   */
  _onFailure(err) {
    this._failureCount++;
    this._lastFailureTime = Date.now();

    if (this._state === CircuitState.HALF_OPEN) {
      // 半开状态下任何失败都立即打开熔断
      this._log.warn(`Half-open failure, reopening circuit: ${err.message}`);
      this._transitionTo(CircuitState.OPEN);
    } else if (this._state === CircuitState.CLOSED) {
      this._log.warn(
        `Tool call failed (${this._failureCount}/${this.options.failureThreshold}): ${err.message}`
      );

      if (this._failureCount >= this.options.failureThreshold) {
        this._log.error(
          `Circuit breaker triggered for '${this.options.name}' after ${this._failureCount} consecutive failures`
        );
        this._transitionTo(CircuitState.OPEN);
      }
    }
  }

  /**
   * 状态转换
   * @param {string} newState
   * @private
   */
  _transitionTo(newState) {
    const oldState = this._state;
    this._state = newState;

    if (newState === CircuitState.CLOSED) {
      this._failureCount = 0;
      this._successCount = 0;
      this._halfOpenAttempts = 0;
      this._log.info(`Circuit breaker CLOSED (reset)`);
    } else if (newState === CircuitState.HALF_OPEN) {
      this._successCount = 0;
      this._halfOpenAttempts = 0;
      this._log.info(`Circuit breaker HALF_OPEN (testing after ${this.options.timeout}ms timeout)`);
    } else if (newState === CircuitState.OPEN) {
      this._successCount = 0;
      this._halfOpenAttempts = 0;
      this._log.warn(`Circuit breaker OPEN (blocking tool calls for ${this.options.timeout}ms)`);
    }
  }

  /**
   * 手动重置熔断器
   */
  reset() {
    this._transitionTo(CircuitState.CLOSED);
  }

  /**
   * 获取熔断器状态信息
   * @returns {Object}
   */
  getStatus() {
    return {
      name: this.options.name,
      state: this.getState(),
      failureCount: this._failureCount,
      successCount: this._successCount,
      lastFailureTime: this._lastFailureTime,
      nextRetryTime:
        this._state === CircuitState.OPEN && this._lastFailureTime
          ? new Date(this._lastFailureTime + this.options.timeout).toISOString()
          : null,
      config: {
        failureThreshold: this.options.failureThreshold,
        successThreshold: this.options.successThreshold,
        timeout: this.options.timeout,
      },
    };
  }
}

/**
 * CircuitBreakerRegistry - 熔断器注册表
 * 管理多个工具的熔断器
 */
class CircuitBreakerRegistry {
  constructor() {
    this._breakers = new Map();
    this._log = logger.child('CircuitBreakerRegistry');
  }

  /**
   * 获取或创建熔断器
   * @param {string} name - 熔断器名称（通常为工具名）
   * @param {CircuitBreakerOptions} options - 选项
   * @returns {CircuitBreaker}
   */
  getOrCreate(name, options = {}) {
    if (!this._breakers.has(name)) {
      this._breakers.set(name, new CircuitBreaker({ ...options, name }));
    }
    return this._breakers.get(name);
  }

  /**
   * 获取熔断器（如果不存在返回 null）
   * @param {string} name
   * @returns {CircuitBreaker|null}
   */
  get(name) {
    return this._breakers.get(name) || null;
  }

  /**
   * 检查是否允许执行
   * @param {string} name
   * @returns {boolean}
   */
  canExecute(name) {
    const breaker = this._breakers.get(name);
    return breaker ? breaker.canExecute() : true;
  }

  /**
   * 执行带熔断保护的函数
   * @param {string} name - 熔断器名称
   * @param {Function} fn - 要执行的函数
   * @param {CircuitBreakerOptions} options - 选项（首次创建时使用）
   * @returns {Promise<any>}
   */
  async execute(name, fn, options = {}) {
    const breaker = this.getOrCreate(name, options);
    return breaker.execute(fn);
  }

  /**
   * 获取所有熔断器状态
   * @returns {Object[]}
   */
  getAllStatus() {
    const result = [];
    for (const [name, breaker] of this._breakers) {
      result.push(breaker.getStatus());
    }
    return result;
  }

  /**
   * 重置所有熔断器
   */
  resetAll() {
    for (const breaker of this._breakers.values()) {
      breaker.reset();
    }
    this._log.info('All circuit breakers reset');
  }

  /**
   * 移除熔断器
   * @param {string} name
   */
  remove(name) {
    this._breakers.delete(name);
  }

  /**
   * 清空所有熔断器
   */
  clear() {
    this._breakers.clear();
  }
}

// 导出单例
const globalRegistry = new CircuitBreakerRegistry();

module.exports = {
  CircuitBreaker,
  CircuitBreakerRegistry,
  CircuitState,
  globalCircuitBreaker: globalRegistry,
};
