import { PresenceService } from './presence.service';

describe('PresenceService', () => {
  const pipeline = {
    exists: jest.fn().mockReturnThis(),
    exec: jest.fn(),
  };

  const redis = {
    set: jest.fn(),
    exists: jest.fn(),
    raw: {
      scan: jest.fn(),
      pipeline: jest.fn(() => pipeline),
    },
  };

  let service: PresenceService;

  beforeEach(() => {
    jest.clearAllMocks();
    service = new PresenceService(redis as never);
  });

  it('touches player key with 120s TTL', async () => {
    await service.touch(42n);
    expect(redis.set).toHaveBeenCalledWith('presence:player:42', '1', 120);
  });

  it('checks single player online status', async () => {
    redis.exists.mockResolvedValue(true);
    await expect(service.isOnline(7n)).resolves.toBe(true);
    expect(redis.exists).toHaveBeenCalledWith('presence:player:7');
  });

  it('counts online keys via SCAN', async () => {
    redis.raw.scan
      .mockResolvedValueOnce(['1', ['presence:player:1', 'presence:player:2']])
      .mockResolvedValueOnce(['0', ['presence:player:3']]);

    await expect(service.getOnlineCount()).resolves.toBe(3);
    expect(redis.raw.scan).toHaveBeenCalledWith(
      '0',
      'MATCH',
      'presence:player:*',
      'COUNT',
      200,
    );
  });

  it('filters online ids with pipeline exists', async () => {
    pipeline.exec.mockResolvedValue([
      [null, 1],
      [null, 0],
      [null, 1],
    ]);

    const result = await service.filterOnlineIds([10n, 20n, 30n]);
    expect(result).toEqual(new Set(['10', '30']));
    expect(pipeline.exists).toHaveBeenCalledTimes(3);
    expect(pipeline.exists).toHaveBeenNthCalledWith(1, 'presence:player:10');
    expect(pipeline.exists).toHaveBeenNthCalledWith(2, 'presence:player:20');
    expect(pipeline.exists).toHaveBeenNthCalledWith(3, 'presence:player:30');
  });

  it('returns empty set when no ids provided', async () => {
    await expect(service.filterOnlineIds([])).resolves.toEqual(new Set());
    expect(redis.raw.pipeline).not.toHaveBeenCalled();
  });
});
