#!/usr/bin/env npx tsx
/**
 * Link Props by Matching Game + Player Name
 * For props with numeric IDs, try to match by player name within the same game
 */

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

const prisma = new PrismaClient();

function normalizePlayerName(name: string): string {
  if (!name) return '';
  return name.toLowerCase()
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
    .replace(/[.']/g, '')
    .replace(/\s+(jr|sr|iii|ii|iv|v)$/i, '')
    .replace(/\s+/g, ' ')
    .trim();
}

async function linkPropsByGamePlayer() {
  console.log('='.repeat(60));
  console.log('LINKING PROPS BY GAME + PLAYER NAME');
  console.log('='.repeat(60) + '\n');

  for (const league of ['nba', 'nfl', 'nhl']) {
    console.log(`\nProcessing ${league.toUpperCase()}...`);

    // Get unlinked props that have a gameId
    const unlinkedProps = await prisma.playerPropLine.findMany({
      where: {
        league,
        canonicalPlayerId: null,
        gameId: { not: null }
      },
      select: {
        id: true,
        playerExternalId: true,
        gameId: true
      },
      take: 10000
    });

    console.log(`  Found ${unlinkedProps.length} unlinked props with gameId`);

    // Group by gameId
    const byGame = new Map<string, typeof unlinkedProps>();
    for (const prop of unlinkedProps) {
      if (!prop.gameId) continue;
      const existing = byGame.get(prop.gameId) || [];
      existing.push(prop);
      byGame.set(prop.gameId, existing);
    }

    let linked = 0;
    let gamesProcessed = 0;

    for (const [gameId, props] of byGame) {
      // Find the canonical game - convert gameId to string for matching
      const gameIdStr = String(gameId);
      const canonicalGame = await prisma.canonicalGame.findFirst({
        where: {
          league,
          OR: [
            { sgoEventId: gameIdStr },
            { bdlGameId: gameIdStr },
            { espnEventId: gameIdStr }
          ]
        },
        include: {
          homeTeam: true,
          awayTeam: true
        }
      });

      if (!canonicalGame) continue;
      gamesProcessed++;

      // Get players from both teams
      const homePlayers = await prisma.canonicalPlayer.findMany({
        where: { league, teamId: canonicalGame.homeTeamId }
      });
      const awayPlayers = await prisma.canonicalPlayer.findMany({
        where: { league, teamId: canonicalGame.awayTeamId }
      });
      const allPlayers = [...homePlayers, ...awayPlayers];

      // Build normalized name lookup
      const playerByNormName = new Map<string, bigint>();
      for (const player of allPlayers) {
        playerByNormName.set(player.normalizedName, player.id);
      }

      // Try to get player names from the Player table or prop metadata
      for (const prop of props) {
        // Look up the Player record
        const player = await prisma.player.findFirst({
          where: { externalId: prop.playerExternalId }
        });

        if (player?.name) {
          const normalized = normalizePlayerName(player.name);
          const canonicalId = playerByNormName.get(normalized);

          if (canonicalId) {
            await prisma.playerPropLine.update({
              where: { id: prop.id },
              data: { canonicalPlayerId: canonicalId }
            });
            linked++;

            // Create alias
            try {
              await prisma.playerAlias.create({
                data: {
                  playerId: canonicalId,
                  source: 'game_match',
                  alias: prop.playerExternalId,
                  aliasType: 'external_id'
                }
              });
            } catch (e) { /* ignore duplicates */ }
          }
        }
      }
    }

    console.log(`  Processed ${gamesProcessed} games, linked ${linked} props`);
  }

  // Final coverage
  console.log('\n' + '='.repeat(60));
  console.log('FINAL PROP COVERAGE');
  console.log('='.repeat(60) + '\n');

  for (const league of ['nba', 'nfl', 'nhl', 'mlb']) {
    const total = await prisma.playerPropLine.count({ where: { league } });
    const linked = await prisma.playerPropLine.count({
      where: { league, NOT: { canonicalPlayerId: null } }
    });
    const pct = total > 0 ? ((linked / total) * 100).toFixed(1) : '0';
    console.log(`${league.toUpperCase()} Props: ${linked.toLocaleString()}/${total.toLocaleString()} (${pct}%)`);
  }

  await prisma.$disconnect();
}

linkPropsByGamePlayer().catch(e => {
  console.error('Failed:', e);
  process.exit(1);
});
