import { HealthCheckError } from '@nestjs/terminus';
import { RedisHealthIndicator } from '../redis.health';

describe('RedisHealthIndicator', () => {
  let indicator: RedisHealthIndicator;
  let mockClient: { ping: ReturnType<typeof vi.fn> };
  let mockRedisService: { getClient: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockClient = { ping: vi.fn() };
    mockRedisService = { getClient: vi.fn().mockReturnValue(mockClient) };
    indicator = new RedisHealthIndicator(mockRedisService as any);
  });

  it('returns healthy status when Redis responds with PONG', async () => {
    mockClient.ping.mockResolvedValue('PONG');

    const result = await indicator.isHealthy('redis');

    expect(mockRedisService.getClient).toHaveBeenCalledOnce();
    expect(mockClient.ping).toHaveBeenCalledOnce();
    expect(result).toEqual({ redis: { status: 'up' } });
  });

  it('throws HealthCheckError when Redis does not respond with PONG', async () => {
    mockClient.ping.mockResolvedValue('NOT_PONG');

    await expect(indicator.isHealthy('redis')).rejects.toThrow(HealthCheckError);
  });

  it('throws HealthCheckError with ping-failed message for non-PONG response', async () => {
    mockClient.ping.mockResolvedValue('');

    try {
      await indicator.isHealthy('redis');
      expect.unreachable('Should have thrown');
    } catch (error) {
      expect(error).toBeInstanceOf(HealthCheckError);
      expect((error as HealthCheckError).message).toBe('Redis ping failed');
    }
  });

  it('throws HealthCheckError when client.ping throws', async () => {
    mockClient.ping.mockRejectedValue(new Error('Connection refused'));

    await expect(indicator.isHealthy('redis')).rejects.toThrow(HealthCheckError);
  });

  it('includes the key name in error status when connection fails', async () => {
    mockClient.ping.mockRejectedValue(new Error('ECONNREFUSED'));

    try {
      await indicator.isHealthy('cache');
      expect.unreachable('Should have thrown');
    } catch (error) {
      expect(error).toBeInstanceOf(HealthCheckError);
      expect((error as HealthCheckError).causes).toEqual({ cache: { status: 'down' } });
    }
  });
});
