'use strict';

/**
 * Book comparison (Session 28).
 *
 * Surfaces the same prop across every available sportsbook with the best
 * line highlighted. Data source is the grouped odds-api prop shape, which
 * already carries book-by-book lines:
 *   { player, stat_type, lines: [{ book, line, over_odds, under_odds }] }
 *
 * "Best line" = highest decimal payout for the selected side. Savings is
 * the per-$100 payout edge of the best book over the field average — the
 * concrete dollars a user leaves on the table by not line-shopping.
 *
 * Zero credits: it only reads odds already fetched/cached.
 */

const { __internals } = require('./parlayService');
const { americanToDecimal } = __internals;

function average(nums) {
  const valid = nums.filter((n) => Number.isFinite(n));
  if (valid.length === 0) return 0;
  return valid.reduce((a, b) => a + b, 0) / valid.length;
}

function oddsForSide(line, side) {
  if (!line) return null;
  const raw = side === 'under' ? line.under_odds : line.over_odds;
  return raw == null ? null : Number(raw);
}

/**
 * Compare one grouped prop across its books for a given side.
 * Returns null when there are no usable book lines.
 */
function compareProp(prop, side = 'over') {
  const books = (prop?.lines || prop?.books || []).filter((b) => b && b.book);
  const priced = books.filter((b) => Number.isFinite(oddsForSide(b, side)));
  if (priced.length === 0) return null;

  let best = priced[0];
  for (const b of priced) {
    if (americanToDecimal(oddsForSide(b, side)) > americanToDecimal(oddsForSide(best, side))) best = b;
  }

  const bestDecimal = americanToDecimal(oddsForSide(best, side));
  const avgDecimal = average(priced.map((b) => americanToDecimal(oddsForSide(b, side))));
  const savings = Math.round((bestDecimal - avgDecimal) * 100 * 100) / 100; // per $100, 2dp

  return {
    player: prop.player,
    stat: prop.stat_type || prop.stat,
    line: best.line ?? prop.line ?? null,
    side,
    books: priced.map((b) => ({
      book: b.book,
      line: b.line ?? null,
      over_odds: b.over_odds ?? null,
      under_odds: b.under_odds ?? null,
      isBest: b.book === best.book,
    })),
    bestBook: best.book,
    bestOdds: oddsForSide(best, side),
    bookCount: priced.length,
    savings,
  };
}

/**
 * Best lines across a list of props, sorted by savings desc (where line-
 * shopping matters most). Drops props with a single book (nothing to
 * compare). `limit` caps the result.
 */
function bestLines(props, { side = 'over', limit = 20 } = {}) {
  if (!Array.isArray(props)) return [];
  const out = [];
  for (const prop of props) {
    const cmp = compareProp(prop, side);
    if (cmp && cmp.bookCount >= 2) out.push(cmp);
  }
  out.sort((a, b) => b.savings - a.savings);
  return limit > 0 ? out.slice(0, limit) : out;
}

module.exports = {
  compareProp,
  bestLines,
  __internals: { average, oddsForSide },
};
