const request = require('supertest');

const mockGetOdds = jest.fn();
jest.mock('../../src/services/oddsService', () => {
  const actual = jest.requireActual('../../src/services/oddsService');
  return {
    ...actual,
    getOdds: (...args) => mockGetOdds(...args),
  };
});

const mockRedis = { get: jest.fn(), set: jest.fn(), hset: jest.fn(), hgetall: jest.fn(), expire: jest.fn() };
jest.mock('../../src/utils/redis', () => ({
  getRedisClient: () => mockRedis,
  cacheGet: async () => null,
  cacheSet: async () => true,
  cacheDel: async () => true,
  isDegraded: () => false,
}));

const { SOCCER_SPORT_KEYS } = require('../../src/services/oddsService');
const app = require('../../src/app');

beforeEach(() => {
  mockGetOdds.mockReset();
  mockRedis.get.mockResolvedValue(null);
});

describe('SOCCER_SPORT_KEYS export', () => {
  test('contains all 9 launch leagues', () => {
    expect(SOCCER_SPORT_KEYS).toEqual(expect.arrayContaining([
      'soccer_wc',
      'soccer_epl',
      'soccer_laliga',
      'soccer_bundesliga',
      'soccer_seriea',
      'soccer_ligue1',
      'soccer_ucl',
      'soccer_mls',
      'soccer_ligamx',
    ]));
    expect(SOCCER_SPORT_KEYS).toHaveLength(9);
  });
});

describe('GET /api/odds/soccer/:league', () => {
  test('valid league reaches getOdds with the prefixed key', async () => {
    mockGetOdds.mockResolvedValueOnce({
      props: [], updated_at: '2026-06-15T00:00:00Z', source: 'live', quota_remaining: 4000,
    });
    const res = await request(app).get('/api/odds/soccer/wc').expect(200);
    expect(mockGetOdds).toHaveBeenCalledWith('soccer_wc');
    expect(res.body.sport).toBe('soccer_wc');
    expect(Array.isArray(res.body.props)).toBe(true);
  });

  test('unknown league returns 400 with valid-list hint', async () => {
    const res = await request(app).get('/api/odds/soccer/spaceleague').expect(400);
    expect(res.body.error).toMatch(/Unknown soccer league/);
    expect(res.body.error).toMatch(/wc/);
    expect(mockGetOdds).not.toHaveBeenCalled();
  });

  test('EPL route works (proves it is not WC-only)', async () => {
    mockGetOdds.mockResolvedValueOnce({
      props: [{ player: 'X', stat_type: 'goals', line: 0.5 }], updated_at: '2026-06-15T00:00:00Z', source: 'cache',
    });
    const res = await request(app).get('/api/odds/soccer/epl').expect(200);
    expect(mockGetOdds).toHaveBeenCalledWith('soccer_epl');
    expect(res.body.sport).toBe('soccer_epl');
  });

  test('case-insensitive league path', async () => {
    mockGetOdds.mockResolvedValueOnce({ props: [], updated_at: 't', source: 'cache' });
    await request(app).get('/api/odds/soccer/LIGAMX').expect(200);
    expect(mockGetOdds).toHaveBeenCalledWith('soccer_ligamx');
  });

  test('getOdds throwing surfaces as a status code, not a 500 leak', async () => {
    const err = new Error('Odds data temporarily unavailable.');
    err.statusCode = 429;
    mockGetOdds.mockRejectedValueOnce(err);
    const res = await request(app).get('/api/odds/soccer/wc').expect(429);
    expect(res.body.error).toMatch(/temporarily unavailable/);
  });
});

describe('existing NBA/NCAAB routes still work (no regression)', () => {
  test('/api/odds/nba still returns the NBA shape', async () => {
    mockGetOdds.mockResolvedValueOnce({
      props: [], updated_at: 't', source: 'cache', quota_remaining: 4000,
    });
    const res = await request(app).get('/api/odds/nba').expect(200);
    expect(res.body.sport).toBe('nba');
    expect(mockGetOdds).toHaveBeenCalledWith('nba');
  });
});
