/* ============================================================
   VYNDR 2.0 — odds formatting + region presets (§9).
   Plain CommonJS so components import it (allowJs) AND Jest tests it.

   CRITICAL (the #1 i18n footgun): fmtOdds only converts MONEYLINES —
   bare signed-integer strings (+150 / -110) or integer numbers (the
   grade→odds map). Totals/lines/spreads like 228.5, 229, -7.5 PASS
   THROUGH UNCHANGED. Apply to moneylines/book odds/parlay legs; NEVER
   to O/U totals or stat lines.

   This deliberately DEVIATES from the prototype's parseAm, whose regex
   accepted decimals (`228.5` would have been mis-converted to a fake
   implied % on O/U cells). The prompt's spec is authoritative here.
   ============================================================ */

const REGIONS = {
  US: { label: 'United States', odds: 'american', currency: 'USD' },
  UK: { label: 'United Kingdom', odds: 'fractional', currency: 'GBP' },
  EU: { label: 'Europe', odds: 'decimal', currency: 'EUR' },
  BR: { label: 'Brazil', odds: 'decimal', currency: 'BRL' },
  AU: { label: 'Australia', odds: 'decimal', currency: 'AUD' },
};

const CURRENCIES = { USD: '$', GBP: '£', EUR: '€', BRL: 'R$', AUD: 'A$' };

const ODDS_FORMATS = ['american', 'decimal', 'fractional', 'implied'];

function gcd(a, b) {
  a = Math.abs(a);
  b = Math.abs(b);
  while (b) {
    [a, b] = [b, a % b];
  }
  return a || 1;
}

/**
 * Return the American-odds integer for a moneyline input, or null if the
 * value is NOT a moneyline (and must pass through unchanged).
 *   - number → only an integer counts (the grade→odds map); 228.5 → null
 *   - string → only an explicitly SIGNED integer (+150 / -110); "228.5",
 *     "229", "-7.5" → null
 */
function parseMoneyline(value) {
  if (typeof value === 'number') return Number.isInteger(value) ? value : null;
  if (typeof value !== 'string') return null;
  return /^[+-]\d+$/.test(value.trim()) ? parseInt(value, 10) : null;
}

function americanToDecimal(am) {
  return am > 0 ? am / 100 + 1 : 100 / -am + 1;
}

/**
 * Format an odds value into the requested style. Non-moneyline inputs are
 * returned verbatim (the pass-through guarantee).
 */
function fmtOdds(value, format = 'american') {
  const am = parseMoneyline(value);
  if (am === null) return value;
  if (format === 'american') return (am > 0 ? '+' : '') + Math.round(am);
  const dec = americanToDecimal(am);
  if (format === 'decimal') return dec.toFixed(2);
  if (format === 'implied') return Math.round((1 / dec) * 100) + '%';
  // fractional
  let n;
  let d;
  if (am > 0) {
    n = Math.round(am);
    d = 100;
  } else {
    n = 100;
    d = Math.round(-am);
  }
  const g = gcd(n, d);
  return `${n / g}/${d / g}`;
}

/** Region → { odds, currency, currencySymbol } preset (§9). */
function regionPreset(region) {
  const r = REGIONS[region] || REGIONS.US;
  return { odds: r.odds, currency: r.currency, currencySymbol: CURRENCIES[r.currency] || '$' };
}

function currencySymbol(code) {
  return CURRENCIES[code] || '$';
}

module.exports = {
  REGIONS,
  CURRENCIES,
  ODDS_FORMATS,
  parseMoneyline,
  americanToDecimal,
  fmtOdds,
  regionPreset,
  currencySymbol,
};
