/**
 * Shared odds math. Extracted so adapters don't duplicate the formulas
 * (and don't subtly diverge — one off-by-one rounding in implied prob
 * breaks CLV history).
 *
 * American odds convention:
 *   +150 → win $150 on a $100 bet
 *   -150 → win $100 on a $150 bet
 */

function oddsToImplied(odds) {
  const n = Number(odds);
  if (!Number.isFinite(n) || n === 0) return null;
  if (n > 0) return 100 / (n + 100);
  return Math.abs(n) / (Math.abs(n) + 100);
}

function impliedToAmerican(prob) {
  const p = Number(prob);
  if (!Number.isFinite(p) || p <= 0 || p >= 1) return null;
  if (p >= 0.5) return Math.round((-100 * p) / (1 - p));
  return Math.round((100 * (1 - p)) / p);
}

// Vig removal: each book bakes profit into both sides. Normalizing the
// over+under implied probs back to 1.0 gives the book's *fair* estimate.
function devig(overOdds, underOdds) {
  const io = oddsToImplied(overOdds);
  const iu = oddsToImplied(underOdds);
  if (io == null || iu == null) return null;
  const total = io + iu;
  if (total <= 0) return null;
  return { fairOver: io / total, fairUnder: iu / total };
}

// Positive CLV = we beat the close = real edge. We compare *fair* probs
// rather than raw odds so vig doesn't flip the sign on us.
function clv(gradedFairProb, closingFairProb) {
  const g = Number(gradedFairProb);
  const c = Number(closingFairProb);
  if (!Number.isFinite(g) || !Number.isFinite(c)) return null;
  return c - g;
}

module.exports = { oddsToImplied, impliedToAmerican, devig, clv };
