// Verify computeFeaturesForProp routes soccer → soccerFeatureExtractor
// and NBA → existing path. The NBA path's full behavior is covered by
// computeFeatures.test.js (existing).

const mockExtractSoccerFeatures = jest.fn();
jest.mock('../../src/services/intelligence/soccerFeatureExtractor', () => ({
  extractSoccerFeatures: (...args) => mockExtractSoccerFeatures(...args),
  isSoccerSport: (s) => ['soccer', 'football'].includes(String(s || '').toLowerCase()),
}));

// Mock the rest of the upstream chain — none of it should be called on
// the soccer branch.
jest.mock('../../src/utils/supabase', () => ({
  getSupabaseServiceClient: () => ({ from: jest.fn() }),
}));
jest.mock('axios');
jest.mock('../../src/services/intelligence/featureCache', () => ({
  getFeatures: jest.fn(),
  // Session 63 — computeFeatures now sources normalized per-game rows here
  // (feeds consistency + the probability estimator + game_count_in_7d).
  getStatRows: jest.fn(async () => []),
  gameCountInWindow: jest.fn(() => null),
}));
jest.mock('../../src/services/intelligence/trapDetection', () => ({
  getTrapScore: jest.fn(async () => ({ composite: 0.2, signals: {}, active_count: 1, recommendation: 'caution' })),
}));
jest.mock('../../src/services/intelligence/consistencyScore', () => ({
  getConsistency: jest.fn(),
}));
jest.mock('../../src/services/intelligence/gameLogService', () => ({
  getGameLogs: jest.fn(async () => []),
}));

const { computeFeaturesForProp } = require('../../src/services/intelligence/computeFeatures');

beforeEach(() => {
  mockExtractSoccerFeatures.mockReset();
});

describe('computeFeaturesForProp — sport dispatch', () => {
  test('sport=soccer routes to soccerFeatureExtractor (NBA path NOT invoked)', async () => {
    mockExtractSoccerFeatures.mockResolvedValueOnce({
      features: { goals_per_90: 0.4 },
      trap: { composite: 0, signals: {}, active_count: 0, recommendation: 'proceed' },
      consistency: { consistency: 'unknown', score: null, games: 0 },
      prop: { line: 0.5, direction: 'over' },
      meta: { player: 'Test', sport: 'soccer', statType: 'goals', errors: [] },
    });

    const result = await computeFeaturesForProp({
      player: 'Test', stat_type: 'goals', line: 0.5, direction: 'over', sport: 'soccer',
    });

    expect(mockExtractSoccerFeatures).toHaveBeenCalledTimes(1);
    expect(result.features.goals_per_90).toBe(0.4);
    expect(result.meta.sport).toBe('soccer');
    // The branch re-runs trap detection so the trap object is populated.
    expect(result.trap.composite).toBeGreaterThanOrEqual(0);
  });

  test('sport=football is normalized into the soccer branch', async () => {
    mockExtractSoccerFeatures.mockResolvedValueOnce({
      features: {}, trap: {}, consistency: {}, prop: {}, meta: { sport: 'soccer', errors: [] },
    });
    await computeFeaturesForProp({ player: 'X', stat_type: 'goals', line: 0.5, sport: 'football' });
    expect(mockExtractSoccerFeatures).toHaveBeenCalledTimes(1);
  });

  test('sport=nba does NOT invoke the soccer extractor', async () => {
    const featureCache = require('../../src/services/intelligence/featureCache');
    featureCache.getFeatures.mockResolvedValueOnce({ features: { l5_avg: 28 } });
    await computeFeaturesForProp({
      player: 'Jokic', stat_type: 'points', line: 26.5, direction: 'over', sport: 'nba',
    });
    expect(mockExtractSoccerFeatures).not.toHaveBeenCalled();
  });

  test('sport omitted defaults to NBA (legacy contract)', async () => {
    const featureCache = require('../../src/services/intelligence/featureCache');
    featureCache.getFeatures.mockResolvedValueOnce({ features: { l5_avg: 30 } });
    await computeFeaturesForProp({ player: 'A', stat_type: 'points', line: 25, direction: 'over' });
    expect(mockExtractSoccerFeatures).not.toHaveBeenCalled();
  });
});
