/**
 * Backfill Historical Prop Data from SportsGameOdds API
 *
 * Based on testing, SGO has historical props going back to:
 * - NBA/NFL: December 2024
 * - NHL/MLB: June 2024
 *
 * Usage:
 *   npx tsx src/scripts/backfillHistoricalProps.ts --league=nba --start=2024-12-01 --end=2025-01-31
 *   npx tsx src/scripts/backfillHistoricalProps.ts --all --dry-run
 */

// Load env synchronously before anything else
require('dotenv').config({ path: '.env.local' });
require('dotenv').config({ path: '.env' });

// Verify API key is set
if (!process.env.SPORTSGAMEODDS_API_KEY) {
  console.error('❌ SPORTSGAMEODDS_API_KEY not set in .env or .env.local');
  process.exit(1);
}

// Now import modules (env is already loaded)
import { fetchGamesOnDemand, FetchResult } from '../lib/onDemandFetch';
import { isSportsDbEnabled, getSportsDb } from '../lib/sportsDb';

// Historical data availability by league (based on our testing)
const HISTORICAL_AVAILABILITY: Record<string, { start: string; description: string }> = {
  nba: { start: '2024-12-01', description: 'Dec 2024 - Present' },
  nfl: { start: '2024-12-01', description: 'Dec 2024 - Present' },
  nhl: { start: '2024-06-01', description: 'Jun 2024 - Present' },
  mlb: { start: '2024-06-01', description: 'Jun 2024 - Present' },
};

interface BackfillOptions {
  league?: string;
  startDate?: string;
  endDate?: string;
  all?: boolean;
  dryRun?: boolean;
  batchDays?: number;
}

function parseArgs(): BackfillOptions {
  const args = process.argv.slice(2);
  const options: BackfillOptions = {
    batchDays: 7, // Fetch 7 days at a time by default
  };

  for (const arg of args) {
    if (arg.startsWith('--league=')) {
      options.league = arg.split('=')[1].toLowerCase();
    } else if (arg.startsWith('--start=')) {
      options.startDate = arg.split('=')[1];
    } else if (arg.startsWith('--end=')) {
      options.endDate = arg.split('=')[1];
    } else if (arg === '--all') {
      options.all = true;
    } else if (arg === '--dry-run') {
      options.dryRun = true;
    } else if (arg.startsWith('--batch=')) {
      options.batchDays = parseInt(arg.split('=')[1], 10);
    }
  }

  return options;
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function addDays(dateStr: string, days: number): string {
  const d = new Date(dateStr);
  d.setDate(d.getDate() + days);
  return d.toISOString().slice(0, 10);
}

function daysBetween(start: string, end: string): number {
  const startDate = new Date(start);
  const endDate = new Date(end);
  return Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
}

async function backfillLeague(
  league: string,
  startDate: string,
  endDate: string,
  options: BackfillOptions
): Promise<{ gamesTotal: number; propsTotal: number; errors: number }> {
  console.log(`\n📥 Backfilling ${league.toUpperCase()} from ${startDate} to ${endDate}`);

  const totalDays = daysBetween(startDate, endDate);
  const batchDays = options.batchDays || 7;
  const batches = Math.ceil(totalDays / batchDays);

  let gamesTotal = 0;
  let propsTotal = 0;
  let errors = 0;
  let currentStart = startDate;

  for (let i = 0; i < batches; i++) {
    const batchEnd = addDays(currentStart, batchDays - 1);
    const effectiveEnd = batchEnd > endDate ? endDate : batchEnd;

    const progress = `[${i + 1}/${batches}]`;
    process.stdout.write(`  ${progress} ${currentStart} to ${effectiveEnd}... `);

    if (options.dryRun) {
      console.log('(dry run - skipped)');
      currentStart = addDays(effectiveEnd, 1);
      continue;
    }

    try {
      const result: FetchResult = await fetchGamesOnDemand({
        league,
        startDate: currentStart,
        endDate: effectiveEnd,
        force: true,
        includeProps: true,
      });

      if (result.fetched) {
        gamesTotal += result.gamesAdded;
        propsTotal += result.propsAdded;
        console.log(`✅ ${result.gamesAdded} games, ${result.propsAdded} props`);
      } else if (result.gamesAdded > 0) {
        console.log(`⚠️  ${result.message} (${result.gamesAdded} existing)`);
      } else {
        console.log(`❌ ${result.message}`);
        if (result.error) errors++;
      }

      // Rate limiting - wait between batches to avoid hitting API limits
      await sleep(2000);
    } catch (error: any) {
      console.log(`❌ Error: ${error?.message || error}`);
      errors++;
    }

    currentStart = addDays(effectiveEnd, 1);
  }

  return { gamesTotal, propsTotal, errors };
}

async function run() {
  const options = parseArgs();

  console.log('🏈 Historical Props Backfill Tool');
  console.log('='.repeat(60));

  if (!process.env.SPORTSGAMEODDS_API_KEY) {
    console.error('❌ SPORTSGAMEODDS_API_KEY not set');
    process.exit(1);
  }

  if (!isSportsDbEnabled()) {
    console.error('❌ SportsDB not enabled');
    process.exit(1);
  }

  if (options.dryRun) {
    console.log('🔍 DRY RUN MODE - No data will be fetched\n');
  }

  // Show current prop counts
  const prisma = getSportsDb();
  const propCount = await prisma.playerPropLine.count();
  const gameCount = await prisma.sportsGame.count();
  console.log(`📊 Current data: ${gameCount.toLocaleString()} games, ${propCount.toLocaleString()} props\n`);

  const endDate = options.endDate || new Date().toISOString().slice(0, 10);
  const results: Record<string, { gamesTotal: number; propsTotal: number; errors: number }> = {};

  if (options.all) {
    console.log('📋 Running backfill for ALL leagues with available historical data:\n');
    for (const [league, info] of Object.entries(HISTORICAL_AVAILABILITY)) {
      console.log(`   ${league.toUpperCase()}: ${info.description}`);
    }

    for (const [league, info] of Object.entries(HISTORICAL_AVAILABILITY)) {
      const start = options.startDate || info.start;
      results[league] = await backfillLeague(league, start, endDate, options);
    }
  } else if (options.league) {
    const info = HISTORICAL_AVAILABILITY[options.league];
    if (!info) {
      console.error(`❌ Unknown league: ${options.league}`);
      console.log('   Available: ' + Object.keys(HISTORICAL_AVAILABILITY).join(', '));
      process.exit(1);
    }

    const start = options.startDate || info.start;
    results[options.league] = await backfillLeague(options.league, start, endDate, options);
  } else {
    console.log('Usage:');
    console.log('  npx tsx src/scripts/backfillHistoricalProps.ts --league=nba');
    console.log('  npx tsx src/scripts/backfillHistoricalProps.ts --league=nfl --start=2025-01-01');
    console.log('  npx tsx src/scripts/backfillHistoricalProps.ts --all');
    console.log('  npx tsx src/scripts/backfillHistoricalProps.ts --all --dry-run');
    console.log('\nOptions:');
    console.log('  --league=LEAGUE   Specific league (nba, nfl, nhl, mlb)');
    console.log('  --start=DATE      Start date (YYYY-MM-DD), defaults to earliest available');
    console.log('  --end=DATE        End date (YYYY-MM-DD), defaults to today');
    console.log('  --all             Backfill all leagues');
    console.log('  --dry-run         Show what would be fetched without fetching');
    console.log('  --batch=N         Days per batch (default: 7)');
    console.log('\nHistorical data availability:');
    for (const [league, info] of Object.entries(HISTORICAL_AVAILABILITY)) {
      console.log(`  ${league.toUpperCase().padEnd(4)}: ${info.description}`);
    }
    process.exit(0);
  }

  // Summary
  console.log('\n' + '='.repeat(60));
  console.log('📋 BACKFILL SUMMARY\n');

  let totalGames = 0;
  let totalProps = 0;
  let totalErrors = 0;

  for (const [league, result] of Object.entries(results)) {
    console.log(`${league.toUpperCase()}: ${result.gamesTotal} games, ${result.propsTotal} props${result.errors > 0 ? `, ${result.errors} errors` : ''}`);
    totalGames += result.gamesTotal;
    totalProps += result.propsTotal;
    totalErrors += result.errors;
  }

  console.log('-'.repeat(40));
  console.log(`TOTAL: ${totalGames} games, ${totalProps} props${totalErrors > 0 ? `, ${totalErrors} errors` : ''}`);

  // Show updated counts
  const newPropCount = await prisma.playerPropLine.count();
  const newGameCount = await prisma.sportsGame.count();
  console.log(`\n📊 Updated data: ${newGameCount.toLocaleString()} games, ${newPropCount.toLocaleString()} props`);
  console.log(`   Added: +${(newGameCount - gameCount).toLocaleString()} games, +${(newPropCount - propCount).toLocaleString()} props`);
}

run().catch(console.error);
