/**
 * Update odds for existing games from SportsGameOdds API
 * Simpler version that focuses on filling in missing odds
 */

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 odds update...\n');

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

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

  // Find games without odds
  const gamesWithoutOdds = await prisma.sportsGame.findMany({
    where: {
      league: league.toLowerCase(),
      season: { in: [2025, 2026] },
      moneylineHome: null,
    },
    orderBy: { gameDate: 'desc' },
    take: 1000,  // Process more games
  });

  console.log(`Games without odds: ${gamesWithoutOdds.length}`);

  let updated = 0;

  // Find the date range we need to query
  const minDate = gamesWithoutOdds.reduce((min, g) => g.gameDate < min ? g.gameDate : min, gamesWithoutOdds[0]?.gameDate || new Date());
  const maxDate = gamesWithoutOdds.reduce((max, g) => g.gameDate > max ? g.gameDate : max, gamesWithoutOdds[0]?.gameDate || new Date());

  // Expand range a bit
  const startDate = new Date(minDate);
  startDate.setDate(startDate.getDate() - 7);
  const endDate = new Date(maxDate);
  endDate.setDate(endDate.getDate() + 7);

  console.log(`Date range: ${startDate.toISOString().split('T')[0]} to ${endDate.toISOString().split('T')[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 >= 2000) break;  // Process more events
    }

    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];
      // Normalize the database team names
      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
      // Keys like: points-home-game-ml-home, points-away-game-ml-away, etc.
      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: points-home-game-ml-home
      const mlHome = odds['points-home-game-ml-home'];
      if (mlHome?.bookOdds) {
        moneylineHome = parseInt(mlHome.bookOdds.replace('+', ''));
      }

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

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

      // Total: points-all-game-ou-over
      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'];
  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')
    GROUP BY league, season
    ORDER BY league, season
  `;
  console.log('\nCurrent coverage:');
  console.table(stats);

  await prisma.$disconnect();
}

main().catch(console.error);
