import type {
  RateLimiter,
  RateLimitResult,
  RateLimitConfig,
  RateLimiterState,
} from "../types.js";

/**
 * Sliding Window Rate Limiter
 *
 * Tracks individual request timestamps and counts requests in a sliding window.
 * More accurate than fixed window but uses more memory.
 */
export class SlidingWindowRateLimiter implements RateLimiter {
  private timestamps: number[] = [];
  private config: RateLimitConfig;

  constructor(config: RateLimitConfig) {
    this.config = config;
  }

  check(): RateLimitResult {
    if (!this.config.enabled) {
      return { allowed: true, headers: {} };
    }

    const now = Date.now();
    const windowStart = now - this.config.windowMs;

    // Remove expired timestamps
    this.timestamps = this.timestamps.filter((t) => t > windowStart);

    const currentCount = this.timestamps.length;
    const remaining = Math.max(0, this.config.maxRequests - currentCount - 1);

    // Calculate when the oldest request will expire
    const oldestTimestamp = this.timestamps[0];
    const resetInSeconds = oldestTimestamp
      ? Math.ceil((oldestTimestamp + this.config.windowMs - now) / 1000)
      : Math.ceil(this.config.windowMs / 1000);

    const headers: Record<string, string> = {
      "x-ratelimit-limit-requests": String(this.config.maxRequests),
      "x-ratelimit-remaining-requests": String(Math.max(0, remaining)),
      "x-ratelimit-reset-requests": `${resetInSeconds}s`,
    };

    if (currentCount >= this.config.maxRequests) {
      const resetInMs = oldestTimestamp
        ? oldestTimestamp + this.config.windowMs - now
        : this.config.windowMs;
      return {
        allowed: false,
        retryAfter: resetInSeconds,
        headers: {
          ...headers,
          "retry-after": String(resetInSeconds),
          "retry-after-ms": String(Math.max(0, resetInMs)),
        },
      };
    }

    // Record this request
    this.timestamps.push(now);

    return { allowed: true, headers };
  }

  reset(): void {
    this.timestamps = [];
  }

  getState(): RateLimiterState {
    const now = Date.now();
    const windowStart = now - this.config.windowMs;
    const activeCount = this.timestamps.filter((t) => t > windowStart).length;

    return {
      strategy: "sliding-window",
      currentCount: activeCount,
      maxCount: this.config.maxRequests,
      windowStartMs: windowStart,
    };
  }

  updateConfig(config: Partial<RateLimitConfig>): void {
    this.config = { ...this.config, ...config };
  }
}
