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

/**
 * After-N Rate Limiter
 *
 * Allows the first N requests, then rejects all subsequent requests.
 * Useful for testing "exhausted quota" scenarios.
 */
export class AfterNRateLimiter implements RateLimiter {
  private totalRequests = 0;
  private config: RateLimitConfig;

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

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

    this.totalRequests++;

    const headers: Record<string, string> = {
      "x-ratelimit-limit-requests": String(this.config.failAfterN),
      "x-ratelimit-remaining-requests": String(
        Math.max(0, this.config.failAfterN - this.totalRequests)
      ),
    };

    if (this.totalRequests > this.config.failAfterN) {
      return {
        allowed: false,
        retryAfter: 60, // Arbitrary - won't actually work until reset
        headers: { ...headers, "retry-after": "60", "retry-after-ms": "60000" },
      };
    }

    return { allowed: true, headers };
  }

  reset(): void {
    this.totalRequests = 0;
  }

  getState(): RateLimiterState {
    return {
      strategy: "after-n",
      currentCount: this.totalRequests,
      maxCount: this.config.failAfterN,
    };
  }

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

/**
 * Random Rate Limiter
 *
 * Randomly rejects requests with a configured probability.
 * Useful for testing retry logic and error handling.
 */
export class RandomRateLimiter implements RateLimiter {
  private config: RateLimitConfig;

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

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

    const headers: Record<string, string> = {
      "x-ratelimit-probability": String(this.config.failProbability),
    };

    if (Math.random() < this.config.failProbability) {
      return {
        allowed: false,
        retryAfter: 1,
        headers: { ...headers, "retry-after": "1", "retry-after-ms": "1000" },
      };
    }

    return { allowed: true, headers };
  }

  reset(): void {
    // No state to reset
  }

  getState(): RateLimiterState {
    return {
      strategy: "random",
    };
  }

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

/**
 * Always Rate Limiter
 *
 * Always rejects requests. Useful for testing rate limit error handling.
 */
export class AlwaysRateLimiter implements RateLimiter {
  private config: RateLimitConfig;

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

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

    return {
      allowed: false,
      retryAfter: 60,
      headers: {
        "x-ratelimit-limit-requests": "0",
        "x-ratelimit-remaining-requests": "0",
        "retry-after": "60",
        "retry-after-ms": "60000",
      },
    };
  }

  reset(): void {
    // No state to reset
  }

  getState(): RateLimiterState {
    return {
      strategy: "always",
    };
  }

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

/**
 * No-op Rate Limiter
 *
 * Never rate limits. Used when rate limiting is disabled.
 */
export class NoOpRateLimiter implements RateLimiter {
  check(): RateLimitResult {
    return { allowed: true, headers: {} };
  }

  reset(): void {}

  getState(): RateLimiterState {
    return { strategy: "none" };
  }

  updateConfig(): void {}
}
