'use strict';

const { canAccess } = require('../config/tiers');

/**
 * Snapshot tier gating (Session 67) — the model price never leaves the server
 * for an unentitled viewer.
 *
 * WHY THIS EXISTS: `GET /api/snapshot/:sport` is PUBLIC and unauthenticated.
 * Session 66 gated `model_odds` on `/api/analyze`, but the snapshot endpoint
 * bypassed that gate entirely and served the model price to anonymous callers
 * on every graded row. This closes it at the same layer as the CLV gate
 * (`routes/ledger.js` columnsFor/stripClv): strip on the way out, never hide
 * in the client.
 *
 * WHAT MUST GO, AND WHY IT IS MORE THAN `model_odds`:
 *   model_odds  the gated number itself.
 *   p_win       model_odds IS `impliedProbToAmerican(p_win)` — shipping p_win
 *               is shipping the price in a different base.
 *   ev_pct      INVERTIBLE. ev is a function of (p_win, book_odds) and
 *               book_odds is public, so p_win — and therefore the price — can
 *               be recovered exactly from it. A gate that leaves ev behind is
 *               not a gate.
 *   value       a boolean over (ev, takeable); with the band public it leaks a
 *   takeable    bound on ev. Cheap to drop, so drop them.
 *
 * WHAT STAYS ON EVERY TIER — deliberately:
 *   book_odds, fair_odds, fair_prob, overround, devig_method.
 * These are MARKET facts and the de-vig of market facts. The de-vigged fair
 * number is the free-tier hook and the hero of the price layer: THE FAIR LEG
 * IS NEVER THE PAYWALL. Only VYNDR's own price gates.
 *
 * `model_price_locked` is stamped on rows that still carry a book+fair pair so
 * the client renders the lock teaser rather than an absent leg — a gated price
 * must never be mistaken for a missing one.
 */

// Model-derived fields. Every one of these can reconstruct the model price.
const MODEL_FIELDS = Object.freeze(['model_odds', 'p_win', 'ev_pct', 'value', 'takeable']);

// Market facts + their de-vig. Never stripped, on any tier.
const MARKET_FIELDS = Object.freeze(['book_odds', 'fair_odds', 'fair_prob', 'overround', 'devig_method']);

/** Does this tier receive VYNDR's own price? */
function entitledToModelPrice(tierName) {
  return canAccess(tierName, 'model_price');
}

/**
 * stripModelPrice(grades, tierName) — returns a NEW array with the
 * model-derived fields removed for unentitled tiers. Entitled tiers get the
 * rows back untouched (same reference — no needless copying on the hot path).
 */
function stripModelPrice(grades, tierName) {
  if (!Array.isArray(grades)) return grades;
  if (entitledToModelPrice(tierName)) return grades;
  return grades.map((g) => {
    if (!g || typeof g !== 'object') return g;
    const out = { ...g };
    for (const f of MODEL_FIELDS) delete out[f];
    // Only flag a LOCK where there is a price story to lock a third leg onto.
    if (out.book_odds != null && out.fair_odds != null) out.model_price_locked = true;
    return out;
  });
}

module.exports = {
  MODEL_FIELDS,
  MARKET_FIELDS,
  entitledToModelPrice,
  stripModelPrice,
};
