import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { RedisService } from '../services/redis.service';

describe('RedisService', () => {
  let redis: RedisService;

  beforeEach(async () => {
    redis = RedisService.getInstance({ url: 'redis://localhost:6379' });
  });

  afterEach(async () => {
    const client = redis.getClient();
    await client.flushdb();
  });

  describe('increment', () => {
    it('should increment counter and set expiry', async () => {
      const count = await redis.increment('test:key', 60);
      expect(count).toBe(1);

      const count2 = await redis.increment('test:key', 60);
      expect(count2).toBe(2);
    });

    it('should set TTL on first increment', async () => {
      await redis.increment('test:ttl', 60);
      const ttl = await redis.getTTL('test:ttl');
      expect(ttl).toBeGreaterThan(0);
      expect(ttl).toBeLessThanOrEqual(60);
    });
  });

  describe('getCounter', () => {
    it('should return 0 for non-existent key', async () => {
      const count = await redis.getCounter('test:nonexistent');
      expect(count).toBe(0);
    });

    it('should return current count', async () => {
      await redis.increment('test:counter', 60);
      await redis.increment('test:counter', 60);
      const count = await redis.getCounter('test:counter');
      expect(count).toBe(2);
    });
  });

  describe('setIfNotExists', () => {
    it('should return true on first set', async () => {
      const result = await redis.setIfNotExists('test:unique', 'value', 60);
      expect(result).toBe(true);
    });

    it('should return false on duplicate set', async () => {
      await redis.setIfNotExists('test:dup', 'value', 60);
      const result = await redis.setIfNotExists('test:dup', 'value', 60);
      expect(result).toBe(false);
    });

    it('should set TTL', async () => {
      await redis.setIfNotExists('test:ttl', 'value', 60);
      const ttl = await redis.getTTL('test:ttl');
      expect(ttl).toBeGreaterThan(0);
      expect(ttl).toBeLessThanOrEqual(60);
    });
  });

  describe('setWithExpiry', () => {
    it('should set value with expiry', async () => {
      const result = await redis.setWithExpiry('test:ex', 'value', 60);
      expect(result).toBe('OK');

      const value = await redis.get('test:ex');
      expect(value).toBe('value');
    });
  });

  describe('get', () => {
    it('should return null for non-existent key', async () => {
      const value = await redis.get('test:missing');
      expect(value).toBeNull();
    });

    it('should return value for existing key', async () => {
      await redis.setWithExpiry('test:get', 'hello', 60);
      const value = await redis.get('test:get');
      expect(value).toBe('hello');
    });
  });

  describe('delete', () => {
    it('should delete a key', async () => {
      await redis.setWithExpiry('test:del', 'value', 60);
      const deleted = await redis.delete('test:del');
      expect(deleted).toBe(1);

      const value = await redis.get('test:del');
      expect(value).toBeNull();
    });
  });

  describe('isConnected', () => {
    it('should return connection status', async () => {
      const connected = await redis.isConnected();
      expect(connected).toBe(true);
    });
  });
});
