import { Redis } from 'ioredis';
import { Store, ClientRateLimitInfo } from 'express-rate-limit';

export class RedisRateLimitStore implements Store {
  readonly prefix: string;

  constructor(
    private readonly client: Redis,
    private readonly windowMs: number,
    prefix = 'rl:',
  ) {
    this.prefix = prefix;
  }

  private key(key: string): string {
    return `${this.prefix}${key}`;
  }

  async increment(key: string): Promise<ClientRateLimitInfo> {
    const redisKey = this.key(key);

    const [hits] = (await this.client
      .multi()
      .incr(redisKey)
      .pexpire(redisKey, this.windowMs)
      .exec()) as [[Error | null, number]];

    const totalHits = hits[1];
    const ttl = await this.client.pttl(redisKey);
    const resetTime = new Date(Date.now() + Math.max(ttl, 0));

    return { totalHits, resetTime };
  }

  async decrement(key: string): Promise<void> {
    const redisKey = this.key(key);
    const current = await this.client.decr(redisKey);
    if (current < 0) {
      await this.client.del(redisKey);
    }
  }

  async resetKey(key: string): Promise<void> {
    await this.client.del(this.key(key));
  }
}
