import { Redis, RedisOptions } from 'ioredis';

export interface RedisServiceConfig {
  url?: string;
  options?: RedisOptions;
}

export class RedisService {
  private static instance: RedisService;
  private client: Redis;

  private constructor(config?: RedisServiceConfig) {
    const url = config?.url || process.env.REDIS_URL || 'redis://localhost:6379';
    this.client = new Redis(url, config?.options || {});
  }

  static getInstance(config?: RedisServiceConfig): RedisService {
    if (!RedisService.instance) {
      RedisService.instance = new RedisService(config);
    }
    return RedisService.instance;
  }

  getClient(): Redis {
    return this.client;
  }

  async isConnected(): Promise<boolean> {
    return this.client.status === 'ready';
  }

  async increment(key: string, expirySeconds?: number): Promise<number> {
    const current = await this.client.incr(key);
    if (current === 1 && expirySeconds) {
      await this.client.expire(key, expirySeconds);
    }
    return current;
  }

  async getCounter(key: string): Promise<number> {
    const value = await this.client.get(key);
    return value ? parseInt(value, 10) : 0;
  }

  async setWithExpiry(key: string, value: string, seconds: number): Promise<'OK' | 1> {
    return this.client.setex(key, seconds, value);
  }

  async setIfNotExists(key: string, value: string, seconds: number): Promise<boolean> {
    const result = await this.client.set(key, value, 'EX', seconds, 'NX');
    return result === 'OK';
  }

  async get(key: string): Promise<string | null> {
    return this.client.get(key);
  }

  async ttl(key: string): Promise<number> {
    return this.client.ttl(key);
  }

  async delete(key: string): Promise<number> {
    return this.client.del(key);
  }

  async getTTL(key: string): Promise<number> {
    return this.client.ttl(key);
  }

  async close(): Promise<void> {
    await this.client.quit();
  }
}
