const mockAxiosGet = jest.fn();
jest.mock('axios', () => ({ get: (...args) => mockAxiosGet(...args) }));

const mockCache = { current: new Map() };
jest.mock('../../src/utils/redis', () => ({
  cacheGet: async (k) => mockCache.current.get(k) ?? null,
  cacheSet: async (k, v) => { mockCache.current.set(k, v); return true; },
  cacheDel: async (k) => { mockCache.current.delete(k); return true; },
}));

jest.mock('../../src/utils/rateLimiter', () => ({
  createLimiter: () => ({ waitForToken: async () => true, snapshot: () => ({}) }),
  createCircuitBreaker: () => ({ call: async (fn) => fn(), snapshot: () => ({}) }),
}));

const injuries = require('../../src/services/intelligence/injuryParser');

beforeEach(() => {
  mockAxiosGet.mockReset();
  mockCache.current.clear();
});

describe('injuryParser.getTeamInjuries', () => {
  test('normalizes ESPN injury payload', async () => {
    mockAxiosGet.mockResolvedValue({
      status: 200,
      data: {
        injuries: [
          { athlete: { id: 3934672, displayName: 'Jalen Brunson' }, status: 'Doubtful', details: { detail: 'Right ankle' } },
          { athlete: { id: 9999, displayName: 'OG Anunoby' }, status: 'Out' },
        ],
      },
    });
    const out = await injuries.getTeamInjuries('nba', 18);
    expect(out).toHaveLength(2);
    expect(out[0]).toMatchObject({ playerId: '3934672', playerName: 'Jalen Brunson', status: 'DOUBTFUL', detail: 'Right ankle' });
    expect(out[1].status).toBe('OUT');
  });

  test('404 is treated as no current injuries (empty list)', async () => {
    mockAxiosGet.mockResolvedValue({ status: 404, data: {} });
    const out = await injuries.getTeamInjuries('nba', 99);
    expect(out).toEqual([]);
  });

  test('cache hit avoids second request', async () => {
    mockAxiosGet.mockResolvedValue({ status: 200, data: { injuries: [] } });
    await injuries.getTeamInjuries('nba', 5);
    await injuries.getTeamInjuries('nba', 5);
    expect(mockAxiosGet).toHaveBeenCalledTimes(1);
  });

  test('returns [] on unsupported sport (no path mapping)', async () => {
    const out = await injuries.getTeamInjuries('curling', 1);
    expect(out).toEqual([]);
  });
});

describe('injuryParser.isPlayerOut + getMissingStarters', () => {
  beforeEach(() => {
    mockAxiosGet.mockResolvedValue({
      status: 200,
      data: {
        injuries: [
          { athlete: { id: 1, displayName: 'A' }, status: 'OUT' },
          { athlete: { id: 2, displayName: 'B' }, status: 'PROBABLE' },
          { athlete: { id: 3, displayName: 'C' }, status: 'DOUBTFUL' },
        ],
      },
    });
  });

  test('isPlayerOut treats OUT and DOUBTFUL as out', async () => {
    expect(await injuries.isPlayerOut('nba', 1, '1')).toBe(true);
    expect(await injuries.isPlayerOut('nba', 1, '3')).toBe(true);
    expect(await injuries.isPlayerOut('nba', 1, '2')).toBe(false);
    expect(await injuries.isPlayerOut('nba', 1, '99')).toBe(false);
  });

  test('getMissingStarters intersects starter set with injured list', async () => {
    const missing = await injuries.getMissingStarters('nba', 1, ['1', '2', '3', '4']);
    expect(missing.map((m) => m.playerId).sort()).toEqual(['1', '3']);
  });
});

describe('injuryParser.extractGameInjuries (from summary JSON)', () => {
  test('reads injuries from competitions[0].competitors[]', async () => {
    const summary = {
      header: {
        competitions: [{
          competitors: [
            { homeAway: 'home', injuries: [{ athlete: { id: 1, displayName: 'H1' }, status: 'Out' }] },
            { homeAway: 'away', injuries: [{ athlete: { id: 2, displayName: 'A1' }, status: 'Probable' }] },
          ],
        }],
      },
    };
    const out = await injuries.getGameInjuries('nba', 'g1', summary);
    expect(out.home).toHaveLength(1);
    expect(out.home[0].status).toBe('OUT');
    expect(out.away[0].status).toBe('PROBABLE');
  });
});
