/**
 * Rate Limiter Service
 * Implements token bucket algorithm for API rate limiting
 * Limits requests to 10 per second for Autotask API
 */

export class RateLimiter {
  private maxRequestsPerSecond: number;
  private requestQueue: Array<() => void> = [];
  private requestTimes: number[] = [];
  private processing = false;

  constructor(maxRequestsPerSecond: number = 10) {
    this.maxRequestsPerSecond = maxRequestsPerSecond;
  }

  /**
   * Throttle a function call to respect rate limits
   * @param fn Function to execute with rate limiting
   * @returns Promise that resolves when function completes
   */
  async throttle<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.requestQueue.push(async () => {
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });

      this.processQueue();
    });
  }

  /**
   * Process the request queue with rate limiting
   */
  private async processQueue(): Promise<void> {
    if (this.processing || this.requestQueue.length === 0) {
      return;
    }

    this.processing = true;

    while (this.requestQueue.length > 0) {
      await this.waitIfNeeded();
      
      const request = this.requestQueue.shift();
      if (request) {
        this.requestTimes.push(Date.now());
        await request();
      }
    }

    this.processing = false;
  }

  /**
   * Wait if we've hit the rate limit
   */
  private async waitIfNeeded(): Promise<void> {
    const now = Date.now();
    const oneSecondAgo = now - 1000;

    // Remove request times older than 1 second
    this.requestTimes = this.requestTimes.filter(time => time > oneSecondAgo);

    // If we've hit the limit, wait until we can make another request
    if (this.requestTimes.length >= this.maxRequestsPerSecond) {
      const oldestRequest = this.requestTimes[0];
      const waitTime = 1000 - (now - oldestRequest) + 10; // Add 10ms buffer
      
      if (waitTime > 0) {
        await this.sleep(waitTime);
      }
    }
  }

  /**
   * Sleep for specified milliseconds
   */
  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * Get current queue length
   */
  getQueueLength(): number {
    return this.requestQueue.length;
  }

  /**
   * Get number of requests in the last second
   */
  getCurrentRequestCount(): number {
    const oneSecondAgo = Date.now() - 1000;
    return this.requestTimes.filter(time => time > oneSecondAgo).length;
  }

  /**
   * Clear the queue and reset
   */
  reset(): void {
    this.requestQueue = [];
    this.requestTimes = [];
    this.processing = false;
  }
}

// Export singleton instance for Autotask API (10 req/sec)
export const autotaskRateLimiter = new RateLimiter(10);

export default autotaskRateLimiter;
