/**
 * Update odds for upcoming games from SportsGameOdds API
 * Focused on games within +/- 7 days of today
 */

import * as dotenv from 'dotenv';
dotenv.config();

import SportsGameOdds from 'sports-odds-api';
import { PrismaClient } from '../prisma_sports/generated/sports-client';
import { normalizeTeam } from '../src/lib/teamNormalization';

const prisma = new PrismaClient();
const API_KEY = process.env.SPORTSGAMEODDS_API_KEY || '';

console.log('API Key loaded:', Boolean(API_KEY));
console.log('Starting upcoming odds update...\n');

const client = new SportsGameOdds({
  apiKeyHeader: API_KEY,
  maxRetries: 2,
  timeout: 30000,
});

async function updateOddsForLeague(league: string) {
  console.log(`\n=== ${league.toUpperCase()} ===`);

  // Focus on upcoming games only (+/- 7 days)
  const now = new Date();
  const startDate = new Date(now);
  startDate.setDate(startDate.getDate() - 7);
  const endDate = new Date(now);
  endDate.setDate(endDate.getDate() + 14);

  // Find games without odds in this range
  const gamesWithoutOdds = await prisma.sportsGame.findMany({
    where: {
      league: league.toLowerCase(),
      season: { in: [2025, 2026] },
      moneylineHome: null,
      gameDate: {
        gte: startDate,
        lte: endDate,
      },
    },
    orderBy: { gameDate: 'asc' },
    take: 500,
  });

  console.log(`Games without odds (${startDate.toISOString().split('T')[0]} to ${endDate.toISOString().split('T')[0]}): ${gamesWithoutOdds.length}`);

  if (gamesWithoutOdds.length === 0) {
    console.log('No games need odds update in this range');
    return 0;
  }

  let updated = 0;

  console.log(`Fetching ${league.toUpperCase()} events from SGO...`);

  try {
    const events: any[] = [];
    for await (const event of client.events.get({
      leagueID: league.toUpperCase(),
      startsAfter: startDate.toISOString(),
      startsBefore: endDate.toISOString(),
    })) {
      events.push(event);
      if (events.length >= 500) break;
    }

    console.log(`Fetched ${events.length} events`);

    // Build a map of events by normalized team matchup
    const eventMap = new Map<string, any>();
    for (const event of events) {
      const rawHome = event.teams?.home?.names?.short || '';
      const rawAway = event.teams?.away?.names?.short || '';
      const homeTeam = normalizeTeam(rawHome, league) || rawHome.toUpperCase();
      const awayTeam = normalizeTeam(rawAway, league) || rawAway.toUpperCase();
      const gameDate = event.status?.startsAt ? new Date(event.status.startsAt).toISOString().split('T')[0] : '';
      const key = `${gameDate}-${homeTeam}-${awayTeam}`;
      eventMap.set(key, event);
    }

    console.log(`Event map has ${eventMap.size} unique matchups`);

    // Match games with events
    let matched = 0;
    for (const game of gamesWithoutOdds) {
      const dateStr = game.gameDate.toISOString().split('T')[0];
      const homeNorm = normalizeTeam(game.homeTeam, league) || game.homeTeam.toUpperCase();
      const awayNorm = normalizeTeam(game.awayTeam, league) || game.awayTeam.toUpperCase();
      const key = `${dateStr}-${homeNorm}-${awayNorm}`;

      const event = eventMap.get(key);
      if (event) matched++;
      if (!event || !event.odds) continue;

      // Extract odds from SGO structure
      let moneylineHome: number | null = null;
      let moneylineAway: number | null = null;
      let spreadHome: number | null = null;
      let total: number | null = null;

      const odds = event.odds as Record<string, any>;

      // Home moneyline
      const mlHome = odds['points-home-game-ml-home'];
      if (mlHome?.bookOdds) {
        moneylineHome = parseInt(mlHome.bookOdds.replace('+', ''));
      }

      // Away moneyline
      const mlAway = odds['points-away-game-ml-away'];
      if (mlAway?.bookOdds) {
        moneylineAway = parseInt(mlAway.bookOdds.replace('+', ''));
      }

      // Home spread
      const spHome = odds['points-home-game-sp-home'];
      if (spHome?.bookSpread) {
        spreadHome = parseFloat(spHome.bookSpread.replace('+', ''));
      }

      // Total
      const totalOver = odds['points-all-game-ou-over'];
      if (totalOver?.bookOverUnder) {
        total = parseFloat(totalOver.bookOverUnder);
      }

      if (moneylineHome) {
        await prisma.sportsGame.update({
          where: { id: game.id },
          data: {
            moneylineHome,
            moneylineAway,
            spreadHome,
            total,
            oddsUpdatedAt: new Date(),
            updatedAt: new Date(),
          },
        });
        updated++;
      }
    }

    console.log(`Matched: ${matched}, Updated: ${updated} games with odds`);

  } catch (e: any) {
    console.error(`Error: ${e.message}`);
  }

  return updated;
}

async function main() {
  const leagues = ['nba', 'nfl', 'nhl', 'mlb', 'ncaab', 'ncaaf'];
  let totalUpdated = 0;

  for (const league of leagues) {
    const updated = await updateOddsForLeague(league);
    totalUpdated += updated;
  }

  console.log(`\n=== TOTAL: ${totalUpdated} games updated with odds ===`);

  // Show updated stats
  const stats = await prisma.$queryRaw`
    SELECT
      league,
      season,
      COUNT(*) as games,
      COUNT(CASE WHEN "moneylineHome" IS NOT NULL THEN 1 END) as with_odds,
      ROUND(100.0 * COUNT(CASE WHEN "moneylineHome" IS NOT NULL THEN 1 END) / COUNT(*), 1) as odds_pct
    FROM "SportsGame"
    WHERE season >= 2025 AND league IN ('nba','nfl','nhl','mlb','ncaab','ncaaf')
    GROUP BY league, season
    ORDER BY league, season
  `;
  console.log('\nCurrent coverage:');
  console.table(stats);

  await prisma.$disconnect();
}

main().catch(console.error);
