#!/usr/bin/env npx tsx
/**
 * Sync Player Stats from ESPN to Database
 *
 * Fetches real player game logs from ESPN and updates the database
 * to ensure player props analysis uses accurate data.
 *
 * Usage:
 *   npx tsx scripts/sync-espn-player-stats.ts              # Sync all NBA players
 *   npx tsx scripts/sync-espn-player-stats.ts --team CHI   # Sync specific team
 */

import { PrismaClient } from '../prisma_sports/generated/sports-client';
import * as fs from 'fs';

const prisma = new PrismaClient();

const ESPN_TEAMS = 'https://site.api.espn.com/apis/site/v2/sports/basketball/nba/teams';

interface GameLogEntry {
  gameDate: Date;
  opponent: string;
  points: number;
  rebounds: number;
  assists: number;
  minutes: number;
  steals: number;
  blocks: number;
}

async function fetchPlayerGameLog(playerId: string): Promise<GameLogEntry[]> {
  try {
    const url = `https://site.web.api.espn.com/apis/common/v3/sports/basketball/nba/athletes/${playerId}/gamelog`;
    const response = await fetch(url);

    if (!response.ok) return [];

    const data = await response.json();
    const events = data?.seasonTypes?.[0]?.categories?.[0]?.events || {};
    const games: GameLogEntry[] = [];

    for (const [gameId, gameData] of Object.entries(events)) {
      const game = gameData as any;
      if (!game.stats) continue;

      // Parse date from gameId or use current date
      const gameDate = new Date();

      games.push({
        gameDate,
        opponent: game.opponent?.abbreviation || '',
        minutes: parseFloat(game.stats[0]) || 0,
        rebounds: parseInt(game.stats[7]) || 0,
        assists: parseInt(game.stats[8]) || 0,
        blocks: parseInt(game.stats[9]) || 0,
        steals: parseInt(game.stats[10]) || 0,
        points: parseInt(game.stats[13]) || 0,
      });
    }

    return games.slice(0, 20);
  } catch (error) {
    return [];
  }
}

async function fetchTeamRoster(teamAbbr: string): Promise<Array<{id: string, name: string}>> {
  try {
    const teamsResponse = await fetch(`${ESPN_TEAMS}?limit=50`);
    const teamsData = await teamsResponse.json();

    const teams = teamsData?.sports?.[0]?.leagues?.[0]?.teams || [];
    const team = teams.find((t: any) =>
      t.team?.abbreviation?.toUpperCase() === teamAbbr.toUpperCase()
    );

    if (!team) return [];

    const rosterUrl = `https://site.api.espn.com/apis/site/v2/sports/basketball/nba/teams/${team.team.id}/roster`;
    const rosterResponse = await fetch(rosterUrl);
    const rosterData = await rosterResponse.json();

    const athletes = rosterData?.athletes || [];
    const roster: Array<{id: string, name: string}> = [];

    for (const item of athletes) {
      if (item?.id) {
        roster.push({ id: item.id, name: item.fullName || '' });
      } else if (item?.items) {
        for (const player of item.items) {
          if (player?.id) {
            roster.push({ id: player.id, name: player.fullName || '' });
          }
        }
      }
    }

    return roster;
  } catch (error) {
    return [];
  }
}

async function getAllTeams(): Promise<string[]> {
  try {
    const response = await fetch(`${ESPN_TEAMS}?limit=50`);
    const data = await response.json();
    const teams = data?.sports?.[0]?.leagues?.[0]?.teams || [];
    return teams.map((t: any) => t.team?.abbreviation).filter(Boolean);
  } catch (error) {
    return [];
  }
}

async function syncTeamStats(teamAbbr: string) {
  console.log(`\nSyncing ${teamAbbr}...`);

  const roster = await fetchTeamRoster(teamAbbr);
  console.log(`  Found ${roster.length} players`);

  const playerStats: any[] = [];

  for (const player of roster) {
    const games = await fetchPlayerGameLog(player.id);

    if (games.length > 0) {
      const last10 = games.slice(0, 10);
      const avg = (arr: number[]) => arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;

      const stats = {
        espnId: player.id,
        name: player.name,
        team: teamAbbr,
        gamesPlayed: games.length,
        seasonAvg: {
          points: Math.round(avg(last10.map(g => g.points)) * 10) / 10,
          rebounds: Math.round(avg(last10.map(g => g.rebounds)) * 10) / 10,
          assists: Math.round(avg(last10.map(g => g.assists)) * 10) / 10,
          minutes: Math.round(avg(last10.map(g => g.minutes)) * 10) / 10,
        },
        last5: {
          points: games.slice(0, 5).map(g => g.points),
          rebounds: games.slice(0, 5).map(g => g.rebounds),
          assists: games.slice(0, 5).map(g => g.assists),
        },
        lastUpdated: new Date().toISOString(),
      };

      playerStats.push(stats);

      // Update database
      try {
        const normalizedName = player.name.toLowerCase()
          .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
          .replace(/\s+(jr\.?|sr\.?|iii|ii|iv|v)$/i, '')
          .replace(/\./g, '').replace(/\s+/g, ' ').trim();

        // Update PlayerGameMetric entries
        for (let i = 0; i < Math.min(games.length, 10); i++) {
          const game = games[i];
          const gameDate = new Date();
          gameDate.setDate(gameDate.getDate() - i);

          for (const [statKey, value] of [
            ['points', game.points],
            ['rebounds', game.rebounds],
            ['assists', game.assists],
          ] as const) {
            await prisma.playerGameMetric.upsert({
              where: {
                league_playerName_gameDate_statKey: {
                  league: 'nba',
                  playerName: player.name,
                  gameDate,
                  statKey,
                },
              },
              create: {
                league: 'nba',
                playerName: player.name,
                team: teamAbbr,
                opponent: game.opponent,
                gameDate,
                statKey,
                value,
              },
              update: {
                value,
                team: teamAbbr,
                opponent: game.opponent,
              },
            });
          }
        }
      } catch (dbError) {
        // Silently continue if DB update fails
      }
    }

    await new Promise(r => setTimeout(r, 50));
  }

  return playerStats;
}

async function main() {
  const args = process.argv.slice(2);
  const teamArg = args.find(a => a.startsWith('--team='))?.split('=')[1]?.toUpperCase();

  console.log('='.repeat(60));
  console.log('SYNC ESPN PLAYER STATS TO DATABASE');
  console.log('='.repeat(60));
  console.log(`Started: ${new Date().toISOString()}`);

  let teams: string[];

  if (teamArg) {
    teams = [teamArg];
  } else {
    teams = await getAllTeams();
  }

  console.log(`\nSyncing ${teams.length} teams...`);

  const allStats: Record<string, any[]> = {};

  for (const team of teams) {
    const stats = await syncTeamStats(team);
    allStats[team] = stats;

    // Delay between teams
    await new Promise(r => setTimeout(r, 200));
  }

  // Save to master file
  const masterPath = '/var/www/html/eventheodds/data/nba_player_stats_master.json';
  fs.writeFileSync(masterPath, JSON.stringify({
    lastUpdated: new Date().toISOString(),
    source: 'ESPN Game Logs',
    teams: allStats,
  }, null, 2));

  console.log(`\n${'='.repeat(60)}`);
  console.log('SYNC COMPLETE');
  console.log(`${'='.repeat(60)}`);
  console.log(`Master file saved to: ${masterPath}`);

  await prisma.$disconnect();
}

main().catch(async (e) => {
  console.error(e);
  await prisma.$disconnect();
  process.exit(1);
});
