/**
 * Tier-based response gating.
 *
 * Free-tier users see the grade letter + confidence + edge (the hook)
 * but the explanation stays locked. Paid tiers see everything. The
 * frontend already has a `tier-locked` CSS class and `BlurredText`
 * component — we just need to mark the locked fields with
 * `locked: true` so the UI knows what to blur.
 *
 * This module is import-once / pure-function — it never reaches into
 * Supabase or Redis. Callers pass the user's tier string; the function
 * returns a new object (does not mutate input).
 */

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

const LOCKED_REASONING_SUMMARY = 'Upgrade to see full analysis.';
const LOCKED_KILL_REASON = 'Upgrade to see details.';

function lockReasoning(reasoning) {
  if (!reasoning || typeof reasoning !== 'object') {
    return { summary: LOCKED_REASONING_SUMMARY, steps: null, locked: true };
  }
  return { summary: LOCKED_REASONING_SUMMARY, steps: null, locked: true };
}

function lockKillConditions(list) {
  if (!Array.isArray(list)) return [];
  return list.map((kc) => ({
    code: kc?.code ?? 'LOCKED',
    reason: LOCKED_KILL_REASON,
    locked: true,
  }));
}

/**
 * applyTierGating — translate a fully-shaped analyzer result into the
 * gated shape appropriate for the caller's tier. The legacy fields
 * (grade, confidence, edge_pct, player, stat_type, line, direction,
 * book) survive untouched on every tier. Only the explanation surface
 * is redacted for free.
 *
 * @param {Object} result — legacy-shaped analyzer output
 * @param {string} tierName — 'free' | 'analyst' | 'desk' | undefined
 * @returns {Object} gated result (new object — input not mutated)
 */
function applyTierGating(result, tierName) {
  if (!result || typeof result !== 'object') return result;

  // Session 62 (A1-S1) — Desk-only intelligence is stripped at the API, not
  // just the adapter: alt line ladder + quarter-Kelly never leave the server
  // for lower tiers. (The pricing page sells them as Desk-only; the gate
  // makes that true at the wire.)
  const deskGated = { ...result };
  if (!canAccess(tierName, 'alt_line_ladder')) delete deskGated.alt_lines;
  if (!canAccess(tierName, 'kelly_sizing')) delete deskGated.kelly;

  // Session 66 — the PRICE TRIPLET's model leg. Free never RECEIVES
  // `model_odds`; it is stripped here, at the wire, not blurred in the client.
  // `book_odds` / `fair_odds` / `ev_pct` deliberately pass through on EVERY
  // tier: the de-vigged fair number is the free-tier hook, and the fair leg is
  // never the paywall. `model_price_locked` tells the card to render the lock
  // teaser rather than an absent leg, so a gated price is never mistaken for a
  // missing one.
  if (!canAccess(tierName, 'model_price')) {
    delete deskGated.model_odds;
    if (deskGated.book_odds != null && deskGated.fair_odds != null) {
      deskGated.model_price_locked = true;
    }
  }

  if (canAccess(tierName, 'reasoning_visible')) {
    // Paid tier — everything else passes through unchanged.
    return deskGated;
  }
  // Free tier: keep grade + confidence + edge_pct (the hook), redact
  // reasoning + kill condition explanations.
  return {
    ...deskGated,
    reasoning: lockReasoning(result.reasoning),
    kill_conditions_triggered: lockKillConditions(result.kill_conditions_triggered),
    tier_gated: true,
    upgrade_hint: 'Upgrade to see full analysis + kill condition details.',
  };
}

module.exports = {
  applyTierGating,
  __internals: {
    lockReasoning,
    lockKillConditions,
    LOCKED_REASONING_SUMMARY,
    LOCKED_KILL_REASON,
  },
};
