import { describe, expect, it } from 'vitest';

import {
  extractCurrentGameOdds,
  getTheOddsPlayerPropMarketKey,
  getTheOddsSportKey,
  matchCurrentGameOdds,
  mergeMissingGameOdds,
  matchHistoricalEvent,
  selectBestPlayerPropOutcome,
  type TheOddsCurrentEvent,
  type TheOddsEventOddsSnapshot,
} from '../the-odds';

describe('the-odds service', () => {
  it('maps Rainmaker leagues and prop stats to TheOdds markets', () => {
    expect(getTheOddsSportKey('nba')).toBe('basketball_nba');
    expect(getTheOddsSportKey('wnba')).toBe('basketball_wnba');
    expect(getTheOddsSportKey('nhl')).toBe('icehockey_nhl');
    expect(getTheOddsSportKey('ligue_1')).toBe('soccer_france_ligue_one');

    expect(getTheOddsPlayerPropMarketKey('nba', 'points')).toBe('player_points');
    expect(getTheOddsPlayerPropMarketKey('wnba', 'threes')).toBe('player_threes');
    expect(getTheOddsPlayerPropMarketKey('nhl', 'shots')).toBe('player_shots_on_goal');
    expect(getTheOddsPlayerPropMarketKey('nhl', 'saves')).toBe('player_total_saves');
    expect(getTheOddsPlayerPropMarketKey('mlb', 'batting_stolenBases')).toBe('batter_stolen_bases');
    expect(getTheOddsPlayerPropMarketKey('epl', 'shots_on_target')).toBe('player_shots_on_target');
    expect(getTheOddsPlayerPropMarketKey('epl', 'goals')).toBeNull();
  });

  it('matches historical events by teams and closest start time', () => {
    const matched = matchHistoricalEvent([
      {
        id: 'wrong-teams',
        sport_key: 'basketball_nba',
        sport_title: 'NBA',
        commence_time: '2026-03-23T00:10:00Z',
        home_team: 'Phoenix Suns',
        away_team: 'Toronto Raptors',
      },
      {
        id: 'target',
        sport_key: 'basketball_nba',
        sport_title: 'NBA',
        commence_time: '2026-03-23T00:10:00Z',
        home_team: 'Boston Celtics',
        away_team: 'Minnesota Timberwolves',
      },
    ], {
      homeTeam: 'Boston Celtics',
      awayTeam: 'Minnesota Timberwolves',
      startsAt: '2026-03-23T00:00:00Z',
    });

    expect(matched?.id).toBe('target');
  });

  it('extracts current soccer odds including h2h, spreads, and totals from the preferred bookmaker', () => {
    const event: TheOddsCurrentEvent = {
      id: 'soccer-1',
      sport_key: 'soccer_epl',
      sport_title: 'EPL',
      commence_time: '2026-04-03T19:00:00Z',
      home_team: 'Rayo Vallecano',
      away_team: 'Elche CF',
      bookmakers: [
        {
          key: 'draftkings',
          title: 'DraftKings',
          markets: [
            {
              key: 'h2h',
              outcomes: [
                { name: 'Rayo Vallecano', price: -135 },
                { name: 'Elche CF', price: 360 },
                { name: 'Draw', price: 260 },
              ],
            },
            {
              key: 'spreads',
              outcomes: [
                { name: 'Rayo Vallecano', price: 217, point: -1.5 },
                { name: 'Elche CF', price: -299, point: 1.5 },
              ],
            },
            {
              key: 'totals',
              outcomes: [
                { name: 'Over', price: 102, point: 2.5 },
                { name: 'Under', price: -125, point: 2.5 },
              ],
            },
          ],
        },
      ],
    };

    expect(extractCurrentGameOdds(event)).toEqual({
      moneyline: { home: -135, away: 360, draw: 260 },
      spread: {
        home: { line: -1.5, odds: 217 },
        away: { line: 1.5, odds: -299 },
      },
      total: {
        over: { line: 2.5, odds: 102 },
        under: { line: 2.5, odds: -125 },
      },
    });
  });

  it('matches current odds by teams/start and only backfills missing market families', () => {
    const matched = matchCurrentGameOdds([
      {
        id: 'soccer-1',
        sport_key: 'soccer_epl',
        sport_title: 'EPL',
        commence_time: '2026-04-03T19:00:00Z',
        home_team: 'Rayo Vallecano',
        away_team: 'Elche CF',
        bookmakers: [
          {
            key: 'fanduel',
            title: 'FanDuel',
            markets: [{
              key: 'h2h',
              outcomes: [
                { name: 'Rayo Vallecano', price: -140 },
                { name: 'Elche CF', price: 360 },
                { name: 'Draw', price: 260 },
              ],
            }],
          },
        ],
      },
    ], {
      homeTeam: 'Rayo Vallecano',
      awayTeam: 'Elche',
      startsAt: '2026-04-03T19:00:00Z',
    });

    expect(mergeMissingGameOdds({
      moneyline: { home: null, away: null },
      spread: {
        home: { line: -1.5, odds: -110 },
        away: { line: 1.5, odds: -110 },
      },
      total: { over: null, under: null },
    }, matched)).toEqual({
      moneyline: { home: -140, away: 360, draw: 260 },
      spread: {
        home: { line: -1.5, odds: -110 },
        away: { line: 1.5, odds: -110 },
      },
      total: { over: null, under: null },
    });
  });

  it('selects the best player prop outcome by player match, line distance, and bookmaker priority', () => {
    const snapshot: TheOddsEventOddsSnapshot = {
      timestamp: '2026-03-22T22:55:37Z',
      eventId: 'evt-1',
      sportKey: 'basketball_nba',
      commenceTime: '2026-03-23T00:10:00Z',
      homeTeam: 'Boston Celtics',
      awayTeam: 'Minnesota Timberwolves',
      bookmakers: [
        {
          key: 'draftkings',
          title: 'DraftKings',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -130, point: 4.5 },
              { name: 'Over', description: 'Mike Conley', price: 102, point: 4.5 },
            ],
          }],
        },
        {
          key: 'fanduel',
          title: 'FanDuel',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -118, point: 5.5 },
              { name: 'Over', description: 'Mike Conley', price: -102, point: 5.5 },
            ],
          }],
        },
      ],
    };

    const selected = selectBestPlayerPropOutcome(snapshot, {
      marketKey: 'player_assists',
      playerName: 'Mike Conley',
      direction: 'under',
      targetLine: 5.5,
      preferNearestLine: true,
    });

    expect(selected).toMatchObject({
      bookmakerKey: 'fanduel',
      odds: -118,
      line: 5.5,
      direction: 'under',
    });
  });

  it('prefers the nearest alternate line over bookmaker priority when a target line is known', () => {
    const snapshot: TheOddsEventOddsSnapshot = {
      timestamp: '2026-03-22T22:55:37Z',
      eventId: 'evt-1',
      sportKey: 'basketball_nba',
      commenceTime: '2026-03-23T00:10:00Z',
      homeTeam: 'Boston Celtics',
      awayTeam: 'Minnesota Timberwolves',
      bookmakers: [
        {
          key: 'fanduel',
          title: 'FanDuel',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -118, point: 6.5 },
            ],
          }],
        },
        {
          key: 'draftkings',
          title: 'DraftKings',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -130, point: 5.5 },
            ],
          }],
        },
      ],
    };

    const selected = selectBestPlayerPropOutcome(snapshot, {
      marketKey: 'player_assists',
      playerName: 'Mike Conley',
      direction: 'under',
      targetLine: 5.5,
      preferNearestLine: false,
    });

    expect(selected).toMatchObject({
      bookmakerKey: 'draftkings',
      odds: -130,
      line: 5.5,
      direction: 'under',
    });
  });

  it('can hard-lock player prop selection to FanDuel when verification requires it', () => {
    const snapshot: TheOddsEventOddsSnapshot = {
      timestamp: '2026-03-22T22:55:37Z',
      eventId: 'evt-1',
      sportKey: 'basketball_nba',
      commenceTime: '2026-03-23T00:10:00Z',
      homeTeam: 'Boston Celtics',
      awayTeam: 'Minnesota Timberwolves',
      bookmakers: [
        {
          key: 'fanduel',
          title: 'FanDuel',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -118, point: 6.5 },
            ],
          }],
        },
        {
          key: 'draftkings',
          title: 'DraftKings',
          markets: [{
            key: 'player_assists',
            outcomes: [
              { name: 'Under', description: 'Mike Conley', price: -130, point: 5.5 },
            ],
          }],
        },
      ],
    };

    const selected = selectBestPlayerPropOutcome(snapshot, {
      marketKey: 'player_assists',
      playerName: 'Mike Conley',
      direction: 'under',
      targetLine: 5.5,
      bookmakerKey: 'fanduel',
    });

    expect(selected).toMatchObject({
      bookmakerKey: 'fanduel',
      odds: -118,
      line: 6.5,
      direction: 'under',
    });
  });
});
