// Unit: hot-list engine (Session 23). Pure function.

const { computeHotList } = require('../../src/services/hotListService');

describe('hotListService', () => {
  test('"hot" means above personal average, not just high raw numbers', () => {
    const players = [
      // 20-PPG player erupting for 28/31/25 → HOT
      { name: 'Riser', games: [{ points: 28 }, { points: 31 }, { points: 25 }, { points: 20 }, { points: 19 }, { points: 21 }, { points: 20 }, { points: 18 }, { points: 22 }, { points: 20 }] },
      // 30-PPG star who dropped 28 recently → NOT hot (below own baseline)
      { name: 'Star', games: [{ points: 28 }, { points: 27 }, { points: 26 }, { points: 31 }, { points: 33 }, { points: 30 }, { points: 32 }, { points: 31 }, { points: 30 }, { points: 33 }] },
    ];
    const list = computeHotList(players, 'nba', { stat: 'points', window: 3 });
    expect(list.map((p) => p.name)).toContain('Riser');
    expect(list.map((p) => p.name)).not.toContain('Star');
  });

  test('returns a ranked list with rank field', () => {
    const players = [
      { name: 'A', games: [{ points: 40 }, { points: 40 }, { points: 10 }, { points: 10 }] },
      { name: 'B', games: [{ points: 22 }, { points: 22 }, { points: 18 }, { points: 18 }] },
    ];
    const list = computeHotList(players, 'nba', { stat: 'points', window: 2 });
    expect(list[0].rank).toBe(1);
    expect(list[0].name).toBe('A'); // biggest jump above baseline
    expect(list[0].delta).toBeGreaterThan(list[1].delta);
  });

  test('uses explicit seasonAvg as baseline when present', () => {
    const players = [
      { name: 'C', seasonAvg: { points: 15 }, games: [{ points: 25 }, { points: 25 }] },
    ];
    const list = computeHotList(players, 'nba', { stat: 'points', window: 2 });
    expect(list[0].baseline).toBe(15);
    expect(list[0].delta).toBe(10);
  });

  test('7-day window filters by date when dates + now supplied', () => {
    const now = new Date('2026-06-12T12:00:00Z').getTime();
    const day = 86_400_000;
    const players = [
      { name: 'D', games: [
        { date: '2026-06-11', hits: 3 }, // in window
        { date: '2026-06-10', hits: 2 }, // in window
        { date: '2026-06-01', hits: 0 }, // outside 7d → baseline
        { date: '2026-05-30', hits: 0 },
      ] },
    ];
    const list = computeHotList(players, 'mlb', { stat: 'hits', windowDays: 7, now });
    expect(list).toHaveLength(1);
    expect(list[0].window).toBe(2);       // only the 2 recent games
    expect(list[0].recentAvg).toBe(2.5);
  });

  test('player with no baseline to trend against is excluded', () => {
    const players = [
      { name: 'E', games: [{ points: 30 }, { points: 30 }] }, // window 7 → no rest, no seasonAvg
    ];
    const list = computeHotList(players, 'nba', { stat: 'points' });
    expect(list).toHaveLength(0);
  });

  test('tie on delta broken by raw recent average', () => {
    const players = [
      { name: 'Low',  games: [{ points: 15 }, { points: 15 }, { points: 10 }, { points: 10 }] }, // +5, recent 15
      { name: 'High', games: [{ points: 25 }, { points: 25 }, { points: 20 }, { points: 20 }] }, // +5, recent 25
    ];
    const list = computeHotList(players, 'nba', { stat: 'points', window: 2 });
    expect(list[0].name).toBe('High');
  });

  test('empty input → empty list', () => {
    expect(computeHotList([], 'nba')).toEqual([]);
    expect(computeHotList(null, 'nba')).toEqual([]);
  });

  test('all/default stat resolves to the sport headline stat', () => {
    const players = [{ name: 'F', games: [{ hits: 3 }, { hits: 3 }, { hits: 0 }, { hits: 0 }] }];
    const list = computeHotList(players, 'mlb', { stat: 'all', window: 2 });
    expect(list[0].stat).toBe('hits');
  });
});
