'use strict';

/**
 * last10Dots — S6 (A1 board, ROW-GRAMMAR §4).
 *
 * ●●○●● — a grade's last 10 REAL games scored against TONIGHT'S locked line:
 * per game, hit = stat value ≥ line → boolean, newest first. Pure math over
 * the `rosterlogs:{sport}` blob the snapshot pipeline already writes (games
 * are stored most-recent-first) — zero API calls, zero new keys.
 *
 * Stat-field access reuses the SAME accessors as streaksService (one source
 * of truth for the several field spellings each feed uses). A stat type with
 * no accessor, an empty log, or a non-finite line → null: absent beats wrong,
 * the UI renders nothing.
 */

const { __internals: streakAccessors } = require('./streaksService');
const { nameKey } = require('../utils/playerName');

const { nba, mlb, soccer } = streakAccessors;

// grade stat_type → streaksService accessor, per sport. Keep keyed on the
// grade-gate stat names (routes/analyze.js vocabulary), not market keys.
const STAT_ACCESSORS = {
  mlb: {
    hits: mlb.hits,
    total_bases: mlb.totalBases,
    home_runs: mlb.homeRuns,
    rbi: mlb.rbi,
    runs: mlb.runs,
    stolen_bases: mlb.stolenBases,
    walks: mlb.walks,
    strikeouts: mlb.strikeouts,
    earned_runs: mlb.earnedRuns,
    hits_allowed: mlb.hits, // pitching log's hits = hits allowed
    innings_pitched: mlb.inningsPitched,
    doubles: mlb.doubles,
    triples: mlb.triples,
    outs: mlb.outs,
  },
  nba: {
    points: nba.points,
    rebounds: nba.rebounds,
    assists: nba.assists,
    threes: nba.threes,
    steals: nba.steals,
    blocks: nba.blocks,
    pra: nba.pra,
  },
  soccer: {
    goals: soccer.goals,
    assists: soccer.assists,
    shots_on_target: soccer.shotsOnTarget,
  },
};
STAT_ACCESSORS.wnba = STAT_ACCESSORS.nba;

const MAX_DOTS = 10;

/**
 * Compute the dot booleans for one player's game log vs a line.
 * `games` most-recent-first (the rosterlogs order). Returns boolean[]
 * (newest first, ≤10) or null when it can't be computed honestly.
 */
function computeLast10Dots(games, sport, statType, line) {
  const sp = String(sport || '').toLowerCase();
  const accessor = (STAT_ACCESSORS[sp] || {})[String(statType || '').toLowerCase()];
  // Strict: Number(null) is 0 — a fabricated line (Data Semantics Rule).
  const ln = line == null ? NaN : Number(line);
  if (!accessor || !Number.isFinite(ln)) return null;
  const rows = Array.isArray(games) ? games.filter(Boolean).slice(0, MAX_DOTS) : [];
  if (rows.length === 0) return null;
  return rows.map((g) => accessor(g) >= ln);
}

/** Index a rosterlogs blob by nameKey → games (most-recent-first). */
function indexRosterLogs(blob) {
  const map = {};
  for (const e of Array.isArray(blob) ? blob : []) {
    if (e && e.name && Array.isArray(e.games) && e.games.length > 0) {
      map[nameKey(e.name)] = e.games;
    }
  }
  return map;
}

/**
 * Attach `last10_dots` to each grade that has a real log + locked line.
 * Non-destructive: grades without a computable strip pass through untouched.
 */
function attachLast10Dots(grades, rosterIndex, sport) {
  if (!rosterIndex || Object.keys(rosterIndex).length === 0) return grades;
  return (grades || []).map((g) => {
    const player = g.player || g.player_name;
    if (!player) return g;
    const games = rosterIndex[nameKey(player)];
    if (!games) return g;
    const line = g.gradedAt && g.gradedAt.line != null ? g.gradedAt.line : g.line;
    const dots = computeLast10Dots(games, sport, g.stat_type || g.stat, line);
    return dots ? { ...g, last10_dots: dots } : g;
  });
}

module.exports = {
  computeLast10Dots,
  indexRosterLogs,
  attachLast10Dots,
  __internals: { STAT_ACCESSORS, MAX_DOTS },
};
