/**
 * ioredis singleton client for rate-limiter-flexible.
 *
 * This client is separate from the `src/cache/redis.ts` client (which uses the
 * `redis` npm package and handles token revocation / OIDC caching).  The
 * rate-limiter-flexible library requires an ioredis-compatible client.
 *
 * Guard: when `REDIS_RATE_LIMIT_ENABLED` is not `"true"` the factory returns
 * `null` and the rate limiter falls back to in-process memory (RateLimiterMemory).
 */

import Redis from 'ioredis';

let ioredisClient: Redis | null = null;

/**
 * Returns a singleton ioredis client for rate limiting, or `null` when Redis
 * rate limiting is disabled via the `REDIS_RATE_LIMIT_ENABLED` env var.
 *
 * The client is lazily initialised on first call. Connection errors are logged
 * but do NOT throw — callers must handle a `null` return and fall back to
 * in-memory rate limiting.
 *
 * @returns The ioredis client instance, or `null` when disabled / unreachable.
 */
export function getRateLimitRedisClient(): Redis | null {
  const enabled = process.env['REDIS_RATE_LIMIT_ENABLED'];
  if (enabled !== 'true') {
    return null;
  }

  if (ioredisClient) {
    return ioredisClient;
  }

  const redisUrl = process.env['REDIS_URL'] ?? 'redis://localhost:6379';

  ioredisClient = new Redis(redisUrl, {
    // Do not throw on connection failure — caller handles null / fallback.
    lazyConnect: false,
    enableReadyCheck: true,
    maxRetriesPerRequest: 1,
    // Reconnect strategy: give up quickly so the health check / fallback fires.
    retryStrategy: (times: number): number | null => {
      if (times >= 3) {
        return null; // stop retrying — triggers 'error' event
      }
      return Math.min(times * 200, 1000);
    },
  });

  ioredisClient.on('error', (err: Error) => {
    // eslint-disable-next-line no-console
    console.error('[RateLimitRedis] Connection error — rate limiter will use memory fallback:', err.message);
    // Reset singleton so next call re-attempts connection.
    ioredisClient = null;
  });

  ioredisClient.on('connect', () => {
    // eslint-disable-next-line no-console
    console.log('[RateLimitRedis] Connected — Redis-backed rate limiting active.');
  });

  return ioredisClient;
}

/**
 * Closes the ioredis rate-limit client and resets the singleton.
 * Used for graceful shutdown and tests.
 *
 * @returns Promise that resolves when the client is disconnected.
 */
export async function closeRateLimitRedisClient(): Promise<void> {
  if (ioredisClient) {
    await ioredisClient.quit();
    ioredisClient = null;
  }
}
