const mockRedis = { get: jest.fn(), set: jest.fn() };
jest.mock('../../src/utils/redis', () => ({ getRedisClient: () => mockRedis }));

const mockSupabaseFrom = jest.fn();
jest.mock('../../src/utils/supabase', () => ({
  getSupabaseServiceClient: () => ({ from: mockSupabaseFrom }),
}));

const { detectScratches } = require('../../src/services/cascadeService');

beforeEach(() => {
  jest.clearAllMocks();
  mockRedis.get.mockResolvedValue(null);
  mockRedis.set.mockResolvedValue('OK');
});

function makeProps(players) {
  const props = [];
  for (const player of players) {
    // Add from 2 books to qualify
    props.push({ player, stat_type: 'points', book: 'draftkings', line: 26.5 });
    props.push({ player, stat_type: 'points', book: 'fanduel', line: 27.0 });
  }
  return props;
}

describe('cascadeService', () => {
  test('first fetch: no previous data, no scratches', async () => {
    mockRedis.get.mockResolvedValue(null);
    const result = await detectScratches('nba', makeProps(['Jokic', 'LeBron']));
    expect(result.scratchedPlayers).toEqual([]);
  });

  test('player present in previous but absent in current: flagged as scratch', async () => {
    // Previous fetch had Jokic + LeBron
    mockRedis.get.mockResolvedValue(JSON.stringify(['Jokic', 'LeBron']));

    // Mock DB queries for processScratches
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'picks') {
        return {
          select: () => ({
            eq: (col, val) => ({
              gte: () => Promise.resolve({ data: [], error: null }),
            }),
          }),
        };
      }
      return {
        select: () => ({ eq: () => ({ gte: () => Promise.resolve({ data: [] }) }) }),
      };
    });

    // Current fetch only has Jokic
    const result = await detectScratches('nba', makeProps(['Jokic']));
    expect(result.scratchedPlayers).toContain('LeBron');
  });

  test('player in only 1 book: not flagged (data gap)', async () => {
    mockRedis.get.mockResolvedValue(JSON.stringify(['Jokic', 'LeBron']));

    // Current: Jokic from 2 books, LeBron from only 1 book
    const props = [
      { player: 'Jokic', stat_type: 'points', book: 'draftkings', line: 26.5 },
      { player: 'Jokic', stat_type: 'points', book: 'fanduel', line: 27.0 },
      { player: 'LeBron', stat_type: 'points', book: 'draftkings', line: 25.5 },
      // LeBron only from 1 book — doesn't qualify as "having props from 2+ books"
    ];

    mockSupabaseFrom.mockReturnValue({
      select: () => ({ eq: () => ({ gte: () => Promise.resolve({ data: [] }) }) }),
    });

    const result = await detectScratches('nba', props);
    // LeBron doesn't qualify for currentPlayers (only 1 book), so flagged as scratch
    expect(result.scratchedPlayers).toContain('LeBron');
  });

  test('no players disappear: empty scratches', async () => {
    mockRedis.get.mockResolvedValue(JSON.stringify(['Jokic', 'LeBron']));

    const result = await detectScratches('nba', makeProps(['Jokic', 'LeBron']));
    expect(result.scratchedPlayers).toEqual([]);
  });
});
