/**
 * Hot lists (Session 23).
 *
 * Rolling recent-window leaders — but through VYNDR's lens. "Hot" does
 * NOT mean "highest raw number." It means performing ABOVE the player's
 * own baseline in the recent window. A 20-PPG player going 28/31/25 is
 * hot; a 30-PPG player who dropped 28 is not.
 *
 * Baseline preference:
 *   1. explicit `player.seasonAvg[stat]` if supplied
 *   2. else the player's own games OUTSIDE the recent window (recent vs rest)
 *
 * If neither baseline is available (a player with only window-length
 * history and no season avg) the player is excluded — we can't claim
 * "trending up" without something to trend against.
 *
 * Pure & deterministic. The route supplies cached logs; this does math.
 */

const { __internals } = require('./streaksService');
const { nba, mlb, soccer } = __internals;

// category → accessor fn, per sport. Mirrors STAT_FILTERS categories.
const HOT_STATS = {
  nba: {
    points: nba.points, rebounds: nba.rebounds, assists: nba.assists,
    threes: nba.threes, blocks: nba.blocks, steals: nba.steals, pra: nba.pra,
  },
  wnba: {
    points: nba.points, rebounds: nba.rebounds, assists: nba.assists,
    threes: nba.threes, blocks: nba.blocks, steals: nba.steals,
  },
  mlb: {
    hits: mlb.hits, home_runs: mlb.homeRuns, stolen_bases: mlb.stolenBases,
    rbis: mlb.rbi, total_bases: mlb.totalBases, strikeouts: mlb.strikeouts,
    on_base: mlb.onBase,
  },
  soccer: {
    goals: soccer.goals, assists: soccer.assists, shots: soccer.shotsOnTarget,
  },
};

// Headline stat per sport when the caller asks for 'all'.
const DEFAULT_STAT = { nba: 'points', wnba: 'points', mlb: 'hits', soccer: 'goals' };

const STAT_LABEL = {
  points: 'pts', rebounds: 'reb', assists: 'ast', threes: '3PM',
  blocks: 'blk', steals: 'stl', pra: 'PRA',
  hits: 'H', home_runs: 'HR', stolen_bases: 'SB', rbis: 'RBI',
  total_bases: 'TB', strikeouts: 'K', on_base: 'OB',
  goals: 'G', shots: 'SOT',
};

function mean(rows, fn) {
  if (!rows.length) return 0;
  return rows.reduce((acc, r) => acc + fn(r), 0) / rows.length;
}

function round1(n) { return Math.round(n * 10) / 10; }

function resolveStat(sport, stat) {
  const table = HOT_STATS[sport] || {};
  if (!stat || stat === 'all') return DEFAULT_STAT[sport] || Object.keys(table)[0] || null;
  return table[stat] ? stat : null;
}

/**
 * Returns a ranked list of hot players for one stat.
 * players = [{ name, playerId, team, games, seasonAvg? }]
 * opts = { stat, window=7, limit, now, windowDays }
 *
 * When rows carry a `date` and `windowDays`+`now` are supplied, the recent
 * window is date-based; otherwise it's the last `window` games.
 */
function computeHotList(players, sport, opts = {}) {
  const key = String(sport || '').toLowerCase();
  const stat = resolveStat(key, opts.stat);
  if (!stat || !Array.isArray(players)) return [];
  const fn = HOT_STATS[key][stat];
  const window = opts.window && opts.window > 0 ? opts.window : 7;

  const rows = [];
  for (const p of players) {
    const games = Array.isArray(p?.games) ? p.games.slice() : [];
    if (games.length === 0) continue;
    if (opts.chronological) games.reverse();

    let recent;
    let rest;
    if (opts.windowDays && opts.now && games[0]?.date) {
      const cutoff = opts.now - opts.windowDays * 86_400_000;
      recent = games.filter((g) => new Date(g.date).getTime() >= cutoff);
      rest = games.filter((g) => new Date(g.date).getTime() < cutoff);
    } else {
      recent = games.slice(0, window);
      rest = games.slice(window);
    }
    if (recent.length === 0) continue;

    const recentAvg = mean(recent, fn);

    // Baseline: explicit season avg, else the player's older games.
    let baseline = null;
    const sa = p.seasonAvg && p.seasonAvg[stat];
    if (sa !== undefined && sa !== null && Number.isFinite(Number(sa))) {
      baseline = Number(sa);
    } else if (rest.length > 0) {
      baseline = mean(rest, fn);
    }
    if (baseline === null) continue;          // nothing to trend against
    if (recentAvg <= baseline) continue;      // not hot — at or below baseline

    const delta = recentAvg - baseline;
    rows.push({
      sport: key,
      stat,
      name: p.name || p.player || null,
      playerId: p.playerId ?? p.id ?? null,
      team: p.team || null,
      recentAvg: round1(recentAvg),
      baseline: round1(baseline),
      delta: round1(delta),
      window: recent.length,
      statLine: `${round1(recentAvg)} ${STAT_LABEL[stat] || stat} over last ${recent.length}`,
      trendDescription: `+${round1(delta)} above ${round1(baseline)} avg`,
    });
  }

  // Rank by how far above baseline (the "trending" signal), then by raw
  // recent average as the tie-breaker (secondary stat).
  rows.sort((a, b) => (b.delta - a.delta) || (b.recentAvg - a.recentAvg));
  const limited = opts.limit && opts.limit > 0 ? rows.slice(0, opts.limit) : rows;
  return limited.map((r, i) => ({ rank: i + 1, ...r }));
}

module.exports = {
  computeHotList,
  resolveStat,
  __internals: { HOT_STATS, DEFAULT_STAT, mean },
};
