/**
 * UnifiedSportsService - Replaces BallDontLie with SportsGameOdds + SportsDB
 *
 * This service provides:
 * - Games, teams, standings from SportsDB (local database)
 * - Live odds, player props from SportsGameOdds API
 * - Same interface as BallDontLieService for easy migration
 */

import { SportsGameOddsClient, LEAGUE_IDS } from '../lib/sportsgameodds';
import { getSportsDb, isSportsDbEnabled } from '../lib/sportsDb';

export type SportsLeague = 'nba' | 'nfl' | 'mlb' | 'nhl' | 'wnba' | 'ncaaf' | 'ncaab' | 'epl' | 'ucl' | string;

// League display names
const LEAGUE_LABELS: Record<string, string> = {
  nba: 'NBA',
  nfl: 'NFL',
  mlb: 'MLB',
  nhl: 'NHL',
  wnba: 'WNBA',
  ncaaf: 'NCAAF',
  ncaab: 'NCAAB',
  epl: 'EPL',
  ucl: 'UCL',
};

// Team abbreviation mappings
const TEAM_ABBREVIATIONS: Record<string, string> = {
  // NBA
  'Atlanta Hawks': 'ATL', 'Boston Celtics': 'BOS', 'Brooklyn Nets': 'BKN',
  'Charlotte Hornets': 'CHA', 'Chicago Bulls': 'CHI', 'Cleveland Cavaliers': 'CLE',
  'Dallas Mavericks': 'DAL', 'Denver Nuggets': 'DEN', 'Detroit Pistons': 'DET',
  'Golden State Warriors': 'GSW', 'Houston Rockets': 'HOU', 'Indiana Pacers': 'IND',
  'Los Angeles Clippers': 'LAC', 'Los Angeles Lakers': 'LAL', 'Memphis Grizzlies': 'MEM',
  'Miami Heat': 'MIA', 'Milwaukee Bucks': 'MIL', 'Minnesota Timberwolves': 'MIN',
  'New Orleans Pelicans': 'NOP', 'New York Knicks': 'NYK', 'Oklahoma City Thunder': 'OKC',
  'Orlando Magic': 'ORL', 'Philadelphia 76ers': 'PHI', 'Phoenix Suns': 'PHX',
  'Portland Trail Blazers': 'POR', 'Sacramento Kings': 'SAC', 'San Antonio Spurs': 'SAS',
  'Toronto Raptors': 'TOR', 'Utah Jazz': 'UTA', 'Washington Wizards': 'WAS',
  // NFL
  'Arizona Cardinals': 'ARI', 'Atlanta Falcons': 'ATL', 'Baltimore Ravens': 'BAL',
  'Buffalo Bills': 'BUF', 'Carolina Panthers': 'CAR', 'Chicago Bears': 'CHI',
  'Cincinnati Bengals': 'CIN', 'Cleveland Browns': 'CLE', 'Dallas Cowboys': 'DAL',
  'Denver Broncos': 'DEN', 'Detroit Lions': 'DET', 'Green Bay Packers': 'GB',
  'Houston Texans': 'HOU', 'Indianapolis Colts': 'IND', 'Jacksonville Jaguars': 'JAX',
  'Kansas City Chiefs': 'KC', 'Las Vegas Raiders': 'LV', 'Los Angeles Chargers': 'LAC',
  'Los Angeles Rams': 'LAR', 'Miami Dolphins': 'MIA', 'Minnesota Vikings': 'MIN',
  'New England Patriots': 'NE', 'New Orleans Saints': 'NO', 'New York Giants': 'NYG',
  'New York Jets': 'NYJ', 'Philadelphia Eagles': 'PHI', 'Pittsburgh Steelers': 'PIT',
  'San Francisco 49ers': 'SF', 'Seattle Seahawks': 'SEA', 'Tampa Bay Buccaneers': 'TB',
  'Tennessee Titans': 'TEN', 'Washington Commanders': 'WAS',
  // NHL
  'Anaheim Ducks': 'ANA', 'Arizona Coyotes': 'ARI', 'Boston Bruins': 'BOS',
  'Buffalo Sabres': 'BUF', 'Calgary Flames': 'CGY', 'Carolina Hurricanes': 'CAR',
  'Chicago Blackhawks': 'CHI', 'Colorado Avalanche': 'COL', 'Columbus Blue Jackets': 'CBJ',
  'Dallas Stars': 'DAL', 'Detroit Red Wings': 'DET', 'Edmonton Oilers': 'EDM',
  'Florida Panthers': 'FLA', 'Los Angeles Kings': 'LAK', 'Minnesota Wild': 'MIN',
  'Montreal Canadiens': 'MTL', 'Nashville Predators': 'NSH', 'New Jersey Devils': 'NJD',
  'New York Islanders': 'NYI', 'New York Rangers': 'NYR', 'Ottawa Senators': 'OTT',
  'Philadelphia Flyers': 'PHI', 'Pittsburgh Penguins': 'PIT', 'San Jose Sharks': 'SJS',
  'Seattle Kraken': 'SEA', 'St. Louis Blues': 'STL', 'Tampa Bay Lightning': 'TBL',
  'Toronto Maple Leafs': 'TOR', 'Vancouver Canucks': 'VAN', 'Vegas Golden Knights': 'VGK',
  'Washington Capitals': 'WSH', 'Winnipeg Jets': 'WPG',
};

export class UnifiedSportsService {
  private static instance: UnifiedSportsService | null = null;
  private sgoClient: SportsGameOddsClient;
  private sportsDb: ReturnType<typeof getSportsDb> | null = null;

  private constructor() {
    this.sgoClient = new SportsGameOddsClient();
    if (isSportsDbEnabled()) {
      this.sportsDb = getSportsDb();
    }
  }

  public static getInstance(): UnifiedSportsService {
    if (!UnifiedSportsService.instance) {
      UnifiedSportsService.instance = new UnifiedSportsService();
    }
    return UnifiedSportsService.instance;
  }

  // For compatibility with code expecting BallDontLieService
  public static resetInstance(): void {
    UnifiedSportsService.instance = null;
  }

  private leaguePrefix(league: SportsLeague): string {
    return league.toLowerCase();
  }

  /**
   * Get teams for a league from SportsDB
   */
  async getTeams(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    if (!this.sportsDb) {
      return { data: [] };
    }

    const leagueLower = league.toLowerCase();

    // Get unique teams from games
    const homeTeams = await this.sportsDb.sportsGame.findMany({
      where: { league: leagueLower },
      distinct: ['homeTeam'],
      select: { homeTeam: true },
    });

    const awayTeams = await this.sportsDb.sportsGame.findMany({
      where: { league: leagueLower },
      distinct: ['awayTeam'],
      select: { awayTeam: true },
    });

    const teamSet = new Set([
      ...homeTeams.map(t => t.homeTeam),
      ...awayTeams.map(t => t.awayTeam),
    ]);

    const teams = [...teamSet].filter(Boolean).sort().map(name => ({
      id: name,
      name: name,
      full_name: name,
      abbreviation: TEAM_ABBREVIATIONS[name] || name.substring(0, 3).toUpperCase(),
    }));

    return { data: teams };
  }

  /**
   * Get players from SportsDB
   */
  async getPlayers(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    if (!this.sportsDb) {
      return { data: [] };
    }

    try {
      const where: any = {};
      if (query.search) {
        where.name = { contains: query.search, mode: 'insensitive' };
      }

      const players = await this.sportsDb.player.findMany({
        where,
        take: query.per_page || 50,
        orderBy: { name: 'asc' },
      });

      return {
        data: players.map(p => ({
          id: p.id,
          first_name: p.name.split(' ')[0],
          last_name: p.name.split(' ').slice(1).join(' '),
          full_name: p.name,
          team: { full_name: p.team, name: p.team },
          position: p.position,
        })),
      };
    } catch (e) {
      console.error('[UnifiedSportsService] getPlayers error:', e);
      return { data: [] };
    }
  }

  /**
   * Get games from SportsDB with optional SGO fallback
   */
  async getGames(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    const leagueLower = league.toLowerCase();

    // Try SportsDB first
    if (this.sportsDb) {
      const where: any = { league: leagueLower };

      // Date filters
      if (query['dates[]']) {
        const date = new Date(query['dates[]']);
        date.setHours(0, 0, 0, 0);
        const nextDay = new Date(date);
        nextDay.setDate(nextDay.getDate() + 1);
        where.gameDate = { gte: date, lt: nextDay };
      } else if (query.start_date || query.end_date) {
        where.gameDate = {};
        if (query.start_date) where.gameDate.gte = new Date(query.start_date);
        if (query.end_date) where.gameDate.lte = new Date(query.end_date);
      }

      // Season filter
      if (query.season || query['seasons[]']) {
        where.season = parseInt(String(query.season || query['seasons[]']), 10);
      }

      // Team filter - filter by team name (home or away)
      if (query.team) {
        const teamPattern = query.team.toLowerCase();
        where.OR = [
          { homeTeam: { contains: teamPattern, mode: 'insensitive' } },
          { awayTeam: { contains: teamPattern, mode: 'insensitive' } },
        ];
      }

      // Week filter for NFL
      if (query.week && leagueLower === 'nfl') {
        // Would need week field in database
      }

      try {
        const games = await this.sportsDb.sportsGame.findMany({
          where,
          orderBy: { gameDate: 'asc' },
          take: query.per_page || 50,
        });

        if (games.length > 0) {
          return {
            data: games.map(g => ({
              id: g.id,
              home_team: { full_name: g.homeTeam, name: g.homeTeam, abbreviation: TEAM_ABBREVIATIONS[g.homeTeam] },
              visitor_team: { full_name: g.awayTeam, name: g.awayTeam, abbreviation: TEAM_ABBREVIATIONS[g.awayTeam] },
              date: g.gameDate.toISOString().split('T')[0],
              datetime: g.gameDate.toISOString(),
              status: g.homeScore !== null ? 'Final' : g.status || 'Scheduled',
              home_team_score: g.homeScore,
              visitor_team_score: g.awayScore,
              // Odds from SportsDB
              moneyline_home: g.moneylineHome,
              moneyline_away: g.moneylineAway,
              spread_home: g.spreadHome,
              spread_away: g.spreadAway,
              total: g.total,
            })),
          };
        }
      } catch (e) {
        console.error('[UnifiedSportsService] SportsDB getGames error:', e);
      }
    }

    // Fallback to SportsGameOdds
    try {
      const leagueKey = leagueLower as keyof typeof LEAGUE_IDS;
      if (LEAGUE_IDS[leagueKey]) {
        const events = await this.sgoClient.getEvents({ league: leagueKey, limit: 50 });
        return {
          data: events.map(e => ({
            id: e.eventId,
            home_team: { full_name: e.homeTeam, name: e.homeTeam },
            visitor_team: { full_name: e.awayTeam, name: e.awayTeam },
            date: e.gameDate.toISOString().split('T')[0],
            datetime: e.gameDate.toISOString(),
            status: e.status.completed ? 'Final' : e.status.started ? 'In Progress' : 'Scheduled',
            home_team_score: null,
            visitor_team_score: null,
            moneyline_home: e.odds.moneylineHome,
            moneyline_away: e.odds.moneylineAway,
            spread_home: e.odds.spreadHome,
            total: e.odds.total,
          })),
        };
      }
    } catch (e) {
      console.error('[UnifiedSportsService] SGO getEvents error:', e);
    }

    return { data: [] };
  }

  /**
   * Get standings calculated from SportsDB game results
   */
  async getStandings(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    if (!this.sportsDb) {
      return { data: [] };
    }

    const leagueLower = league.toLowerCase();
    const season = parseInt(String(query.season || query['seasons[]'] || new Date().getFullYear()), 10);

    try {
      // Get all completed games for the season
      const games = await this.sportsDb.sportsGame.findMany({
        where: {
          league: leagueLower,
          season,
          homeScore: { not: null, gt: 50 },
          awayScore: { not: null, gt: 50 },
        },
      });

      // Calculate standings from game results
      const teamStats: Record<string, {
        wins: number;
        losses: number;
        ties: number;
        otLosses: number;
        pointsFor: number;
        pointsAgainst: number;
        conference?: string;
        division?: string;
      }> = {};

      for (const game of games) {
        const homeScore = game.homeScore ?? 0;
        const awayScore = game.awayScore ?? 0;

        if (!teamStats[game.homeTeam]) {
          teamStats[game.homeTeam] = { wins: 0, losses: 0, ties: 0, otLosses: 0, pointsFor: 0, pointsAgainst: 0 };
        }
        if (!teamStats[game.awayTeam]) {
          teamStats[game.awayTeam] = { wins: 0, losses: 0, ties: 0, otLosses: 0, pointsFor: 0, pointsAgainst: 0 };
        }

        // Track points
        teamStats[game.homeTeam].pointsFor += homeScore;
        teamStats[game.homeTeam].pointsAgainst += awayScore;
        teamStats[game.awayTeam].pointsFor += awayScore;
        teamStats[game.awayTeam].pointsAgainst += homeScore;

        if (homeScore > awayScore) {
          teamStats[game.homeTeam].wins++;
          teamStats[game.awayTeam].losses++;
        } else if (awayScore > homeScore) {
          teamStats[game.awayTeam].wins++;
          teamStats[game.homeTeam].losses++;
        } else {
          // Tie handling - NHL uses OT losses
          if (leagueLower === 'nhl') {
            // In NHL, ties after regulation go to OT - both get 1 point, winner gets extra
            // For simplicity, count as tie here
            teamStats[game.homeTeam].ties++;
            teamStats[game.awayTeam].ties++;
          } else {
            teamStats[game.homeTeam].ties++;
            teamStats[game.awayTeam].ties++;
          }
        }
      }

      // Sort by wins/points
      const standings = Object.entries(teamStats)
        .map(([team, stats]) => {
          // Calculate points for NHL (2 pts win, 1 pt OT loss)
          const points = leagueLower === 'nhl'
            ? stats.wins * 2 + stats.ties
            : undefined;

          const winPct = stats.wins + stats.losses > 0
            ? stats.wins / (stats.wins + stats.losses)
            : 0;

          return {
            team: { full_name: team, name: team, abbreviation: TEAM_ABBREVIATIONS[team] },
            wins: stats.wins,
            losses: stats.losses,
            ties: stats.ties || undefined,
            overtime_losses: stats.otLosses || undefined,
            points, // NHL points
            win_pct: winPct.toFixed(3),
            points_for: stats.pointsFor,
            points_against: stats.pointsAgainst,
            conference: stats.conference,
            division: stats.division,
          };
        })
        .sort((a, b) => {
          // NHL: sort by points
          if (leagueLower === 'nhl' && a.points !== undefined && b.points !== undefined) {
            return b.points - a.points;
          }
          // Others: sort by win percentage
          return parseFloat(b.win_pct) - parseFloat(a.win_pct);
        });

      return { data: standings };
    } catch (e) {
      console.error('[UnifiedSportsService] getStandings error:', e);
      return { data: [] };
    }
  }

  /**
   * Get odds from SportsGameOdds
   */
  async getOdds(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    try {
      const leagueKey = league.toLowerCase() as keyof typeof LEAGUE_IDS;
      if (!LEAGUE_IDS[leagueKey]) {
        console.warn(`[UnifiedSportsService] League ${league} not supported by SportsGameOdds`);
        return { data: [] };
      }

      const events = await this.sgoClient.getEvents({
        league: leagueKey,
        limit: query.per_page || 25,
        oddsAvailable: true,
        started: false,
      });

      return {
        data: events.map(e => ({
          game_id: e.eventId,
          home_team: e.homeTeam,
          away_team: e.awayTeam,
          commence_time: e.gameDate.toISOString(),
          // Main lines
          moneyline_home: e.odds.moneylineHome,
          moneyline_away: e.odds.moneylineAway,
          spread_home: e.odds.spreadHome,
          spread_away: e.odds.spreadAway,
          spread_home_odds: e.odds.spreadHomeOdds,
          spread_away_odds: e.odds.spreadAwayOdds,
          total: e.odds.total,
          total_over_odds: e.odds.totalOverOdds,
          total_under_odds: e.odds.totalUnderOdds,
          // Opening lines
          opening_moneyline_home: e.odds.openingMoneylineHome,
          opening_moneyline_away: e.odds.openingMoneylineAway,
          opening_spread_home: e.odds.openingSpreadHome,
          opening_total: e.odds.openingTotal,
          // Fair odds
          fair_moneyline_home: e.odds.fairMoneylineHome,
          fair_moneyline_away: e.odds.fairMoneylineAway,
          fair_spread: e.odds.fairSpread,
          fair_total: e.odds.fairTotal,
          // Bookmaker breakdown
          bookmakers: e.bookmakerOdds,
        })),
      };
    } catch (e) {
      console.error('[UnifiedSportsService] getOdds error:', e);
      return { data: [] };
    }
  }

  /**
   * Get player props from SportsGameOdds
   */
  async getPlayerProps(league: SportsLeague, gameId?: string | number): Promise<any> {
    try {
      const leagueKey = league.toLowerCase() as keyof typeof LEAGUE_IDS;
      if (!LEAGUE_IDS[leagueKey]) {
        return { data: [] };
      }

      const propsData = await this.sgoClient.getPlayerProps(leagueKey);

      // Filter by gameId if provided
      const filtered = gameId
        ? propsData.filter(p => p.eventId === String(gameId))
        : propsData;

      return {
        data: filtered.flatMap(event =>
          event.props.map(prop => ({
            game_id: event.eventId,
            home_team: event.homeTeam,
            away_team: event.awayTeam,
            game_date: event.gameDate.toISOString(),
            player: { name: prop.playerName, id: prop.playerId },
            stat_type: prop.market,
            line: prop.line,
            over_odds: prop.overOdds,
            under_odds: prop.underOdds,
          }))
        ),
      };
    } catch (e) {
      console.error('[UnifiedSportsService] getPlayerProps error:', e);
      return { data: [] };
    }
  }

  /**
   * Get injuries - placeholder, would need separate data source
   */
  async getInjuries(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    // Injuries not available from SportsGameOdds or basic SportsDB
    // Would need ESPN/official API integration
    return { data: [] };
  }

  /**
   * Get season averages for a player
   */
  async getSeasonAveragesForPlayer(league: SportsLeague, playerId: number | string, season?: number): Promise<any> {
    if (!this.sportsDb) {
      return { data: [] };
    }

    try {
      const metrics = await this.sportsDb.playerGameMetric.findMany({
        where: {
          league: league.toLowerCase(),
          playerExternalId: String(playerId),
          season: season || undefined,
        },
      });

      // Calculate averages from game metrics
      const statSums: Record<string, { total: number; count: number }> = {};
      for (const m of metrics) {
        if (!statSums[m.statKey]) {
          statSums[m.statKey] = { total: 0, count: 0 };
        }
        statSums[m.statKey].total += m.value;
        statSums[m.statKey].count++;
      }

      const averages: Record<string, number> = {};
      for (const [stat, data] of Object.entries(statSums)) {
        averages[stat] = data.total / data.count;
      }

      return { data: [{ player_id: playerId, season, ...averages }] };
    } catch (e) {
      console.error('[UnifiedSportsService] getSeasonAveragesForPlayer error:', e);
      return { data: [] };
    }
  }

  // ============== FORMATTING METHODS ==============

  formatGamesForChat(payload: any, leagueLabel: string, teamFilter?: string): string {
    let games = payload?.data || [];
    if (!games.length) {
      return `No ${leagueLabel} games found.`;
    }

    // Apply team filter if provided (for "Lakers schedule" type queries)
    if (teamFilter) {
      const filterLower = teamFilter.toLowerCase();
      games = games.filter((g: any) => {
        const home = this.extractTeamName(g.home_team, g.homeTeam);
        const away = this.extractTeamName(g.visitor_team, g.awayTeam);
        return home.toLowerCase().includes(filterLower) ||
               away.toLowerCase().includes(filterLower);
      });
      if (!games.length) {
        return `No ${leagueLabel} games found for ${teamFilter}.`;
      }
    }

    const lines = games.slice(0, 15).map((g: any) => {
      // Fix: properly extract team names to avoid [object Object]
      const home = this.extractTeamName(g.home_team, g.homeTeam);
      const away = this.extractTeamName(g.visitor_team, g.awayTeam);
      const date = g.date || g.datetime?.split('T')[0] || '';
      const status = g.status || '';
      const score = g.home_team_score !== null && g.home_team_score !== undefined
        ? `${g.visitor_team_score}-${g.home_team_score}`
        : '';
      return `• ${away} @ ${home} | ${date} | ${status}${score ? ` | ${score}` : ''}`;
    });

    const header = teamFilter
      ? `**${teamFilter} ${leagueLabel} Schedule:**`
      : `**${leagueLabel} Games:**`;
    return `${header}\n${lines.join('\n')}`;
  }

  // Helper to extract team name and avoid [object Object] serialization
  private extractTeamName(teamObj: any, fallback?: string): string {
    if (!teamObj && !fallback) return 'TBD';
    if (typeof teamObj === 'string') return teamObj;
    if (teamObj && typeof teamObj === 'object') {
      return teamObj.name || teamObj.full_name || teamObj.abbreviation || 'TBD';
    }
    return fallback || 'TBD';
  }

  formatStandingsForChat(payload: any, leagueLabel: string): string {
    const standings = payload?.data || [];
    if (!standings.length) {
      return `No ${leagueLabel} standings available.`;
    }

    const isNHL = leagueLabel.toLowerCase().includes('nhl');

    const lines = standings.slice(0, 15).map((s: any, idx: number) => {
      const team = s.team?.full_name || s.team?.name || s.team || 'Unknown';
      const record = isNHL
        ? `${s.wins}-${s.losses}-${s.ties || 0}` // W-L-OTL for NHL
        : `${s.wins}-${s.losses}${s.ties ? `-${s.ties}` : ''}`;
      const extra = isNHL && s.points !== undefined ? ` (${s.points} pts)` : ` (${s.win_pct})`;
      return `${idx + 1}. ${team}: ${record}${extra}`;
    });

    return `**${leagueLabel} Standings:**\n${lines.join('\n')}`;
  }

  formatTeamsForChat(payload: any, leagueLabel: string, options?: { maxItems?: number }): string {
    const teams = payload?.data || [];
    if (!teams.length) {
      return `No ${leagueLabel} teams found.`;
    }

    const max = options?.maxItems || 30;
    const lines = teams.slice(0, max).map((t: any) => {
      const name = t.full_name || t.name;
      const abbr = t.abbreviation ? ` (${t.abbreviation})` : '';
      return `• ${name}${abbr}`;
    });

    return `**${leagueLabel} Teams:**\n${lines.join('\n')}`;
  }

  formatPlayersForChat(payload: any, leagueLabel: string): string {
    const players = payload?.data || [];
    if (!players.length) {
      return `No ${leagueLabel} players found.`;
    }

    const lines = players.slice(0, 20).map((p: any) => {
      const name = p.full_name || `${p.first_name} ${p.last_name}`;
      const team = p.team?.name || p.team?.full_name || p.team || '';
      const pos = p.position ? ` (${p.position})` : '';
      return `• ${name}${pos}${team ? ` - ${team}` : ''}`;
    });

    return `**${leagueLabel} Players:**\n${lines.join('\n')}`;
  }

  formatInjuriesForChat(payload: any, leagueLabel: string): string {
    const injuries = payload?.data || [];
    if (!injuries.length) {
      return `No ${leagueLabel} injury data available.`;
    }

    const lines = injuries.slice(0, 15).map((inj: any) => {
      const player = inj.player?.full_name || inj.player?.name || inj.player_name || 'Unknown';
      const team = inj.team?.name || inj.team || '';
      const status = inj.status || inj.injury_status || 'Unknown';
      const desc = inj.description || inj.injury || '';
      return `• ${player} (${team}): ${status}${desc ? ` - ${desc}` : ''}`;
    });

    return `**${leagueLabel} Injuries:**\n${lines.join('\n')}`;
  }

  formatOddsForChat(payload: any, leagueLabel: string, gamesPayload?: any): string {
    const odds = payload?.data || [];
    if (!odds.length) {
      return `No ${leagueLabel} odds available.`;
    }

    const lines = odds.slice(0, 10).map((o: any) => {
      const home = o.home_team || 'Home';
      const away = o.away_team || 'Away';
      const parts: string[] = [];

      if (o.moneyline_home !== undefined && o.moneyline_away !== undefined) {
        const mlHome = o.moneyline_home > 0 ? `+${o.moneyline_home}` : o.moneyline_home;
        const mlAway = o.moneyline_away > 0 ? `+${o.moneyline_away}` : o.moneyline_away;
        parts.push(`ML: ${mlHome}/${mlAway}`);
      }

      if (o.spread_home !== undefined) {
        const spread = o.spread_home > 0 ? `+${o.spread_home}` : o.spread_home;
        parts.push(`Spread: ${spread}`);
      }

      if (o.total !== undefined) {
        parts.push(`O/U: ${o.total}`);
      }

      return `**${away} @ ${home}**\n  ${parts.join(' | ') || 'No lines available'}`;
    });

    return `**${leagueLabel} Odds (SportsGameOdds):**\n${lines.join('\n')}`;
  }

  formatPlayerPropsForChat(payload: any, leagueLabel: string): string {
    const props = payload?.data || [];
    if (!props.length) {
      return `No ${leagueLabel} player props available.`;
    }

    // Group by game
    const byGame: Record<string, any[]> = {};
    for (const prop of props) {
      const key = `${prop.away_team || 'Away'} @ ${prop.home_team || 'Home'}`;
      if (!byGame[key]) byGame[key] = [];
      byGame[key].push(prop);
    }

    const lines: string[] = [];
    for (const [game, gameProps] of Object.entries(byGame).slice(0, 5)) {
      lines.push(`**${game}:**`);
      for (const prop of gameProps.slice(0, 5)) {
        const player = prop.player?.name || 'Unknown';
        const over = prop.over_odds ? `O${prop.over_odds > 0 ? '+' : ''}${prop.over_odds}` : '';
        const under = prop.under_odds ? `U${prop.under_odds > 0 ? '+' : ''}${prop.under_odds}` : '';
        lines.push(`  • ${player} ${prop.stat_type || prop.market}: ${prop.line} (${[over, under].filter(Boolean).join('/')})`);
      }
    }

    return `**${leagueLabel} Player Props:**\n${lines.join('\n')}`;
  }

  /**
   * Get season averages for all players in a league
   */
  async getSeasonAverages(league: SportsLeague, query: Record<string, any> = {}): Promise<any> {
    if (!this.sportsDb) {
      return { data: [] };
    }

    try {
      const season = parseInt(String(query.season || new Date().getFullYear()), 10);

      // Get aggregated stats from player game metrics
      const metrics = await this.sportsDb.playerGameMetric.groupBy({
        by: ['playerExternalId', 'playerName', 'team', 'statKey'],
        where: {
          league: league.toLowerCase(),
          season,
        },
        _avg: { value: true },
        _count: { value: true },
      });

      // Group by player
      const playerStats: Record<string, any> = {};
      for (const m of metrics) {
        if (!playerStats[m.playerExternalId]) {
          playerStats[m.playerExternalId] = {
            player_id: m.playerExternalId,
            player_name: m.playerName,
            team: m.team,
            games_played: 0,
          };
        }
        playerStats[m.playerExternalId][m.statKey] = m._avg.value;
        playerStats[m.playerExternalId].games_played = Math.max(
          playerStats[m.playerExternalId].games_played,
          m._count.value || 0
        );
      }

      return { data: Object.values(playerStats) };
    } catch (e) {
      console.error('[UnifiedSportsService] getSeasonAverages error:', e);
      return { data: [] };
    }
  }

  /**
   * Format player stats for chat display
   */
  formatPlayerStatsForChat(payload: any, playerName?: string): string {
    const stats = payload?.data || [];
    if (!stats.length) {
      return playerName
        ? `No stats available for ${playerName}.`
        : 'No player stats available.';
    }

    const lines = stats.slice(0, 10).map((s: any) => {
      const name = s.player_name || s.full_name || 'Unknown';
      const team = s.team ? ` (${s.team})` : '';
      const gp = s.games_played ? `GP: ${s.games_played}` : '';

      // Common stat keys
      const statParts: string[] = [];
      if (s.pts || s.points) statParts.push(`${(s.pts || s.points).toFixed(1)} PPG`);
      if (s.reb || s.rebounds) statParts.push(`${(s.reb || s.rebounds).toFixed(1)} RPG`);
      if (s.ast || s.assists) statParts.push(`${(s.ast || s.assists).toFixed(1)} APG`);
      if (s.stl || s.steals) statParts.push(`${(s.stl || s.steals).toFixed(1)} SPG`);
      if (s.blk || s.blocks) statParts.push(`${(s.blk || s.blocks).toFixed(1)} BPG`);
      if (s.fg_pct) statParts.push(`${(s.fg_pct * 100).toFixed(1)}% FG`);
      if (s.fg3_pct) statParts.push(`${(s.fg3_pct * 100).toFixed(1)}% 3P`);

      const statsStr = statParts.length > 0 ? statParts.join(', ') : 'Stats loading...';

      return `**${name}**${team}: ${statsStr}${gp ? ` | ${gp}` : ''}`;
    });

    const header = playerName
      ? `**${playerName} Stats:**`
      : '**Player Stats:**';

    return `${header}\n${lines.join('\n')}`;
  }

  /**
   * Find player by name in SportsDB
   */
  findPlayerByName(league: SportsLeague, playerName: string): any | null {
    // Sync method - would need async implementation with DB
    return null;
  }

  /**
   * Get cache stats - for compatibility
   */
  getCacheStats(): { memoryEntries: number; diskEntries: number; diskSizeMB: number } {
    return { memoryEntries: 0, diskEntries: 0, diskSizeMB: 0 };
  }

  /**
   * Get API usage from SportsGameOdds
   */
  async getApiUsage(): Promise<{ used: number; remaining: number; limit: number }> {
    try {
      return await this.sgoClient.getUsage();
    } catch (e) {
      return { used: 0, remaining: 0, limit: 0 };
    }
  }
}

// Export singleton factory - matching BallDontLie pattern
export function getUnifiedSportsService(): UnifiedSportsService {
  return UnifiedSportsService.getInstance();
}

export default UnifiedSportsService;
