// ═══════════════════════════════════════════════════════════
//  計分引擎 — 把真實數據變成「總經健康分數 + 景氣燈號」
//
//  原則：透明、可解釋。從 50 分（中性）出發，依幾條白話規則
//  加減分，每一條都附在 breakdown 裡，讓初學者看得懂結論怎麼來。
//  分數越高代表總經環境對風險性資產越友善。
// ═══════════════════════════════════════════════════════════

function clamp(n, lo, hi) {
  return Math.max(lo, Math.min(hi, n));
}

// 取得卡片原始值（缺資料回傳 null）
function val(cards, key) {
  const c = cards[key];
  return c && Number.isFinite(c.rawValue) ? c.rawValue : null;
}
function dir(cards, key) {
  return cards[key] ? cards[key].dir : null;
}

export function computeScore(cards) {
  let score = 50;
  const breakdown = [];
  const add = (delta, label, note) => {
    if (delta === 0) return;
    score += delta;
    breakdown.push({ label, delta, note });
  };

  // 1) 殖利率曲線（倒掛是重要衰退警訊）
  const spread = val(cards, 'yield_spread'); // bp
  if (spread != null) {
    if (spread < 0) add(-15, '殖利率曲線', `倒掛 ${Math.round(spread)}bp，歷史上的衰退前兆`);
    else if (spread < 50) add(-4, '殖利率曲線', `偏平 ${Math.round(spread)}bp`);
    else add(6, '殖利率曲線', `正常 ${Math.round(spread)}bp`);
  }

  // 2) 衰退機率模型
  const rec = val(cards, 'recession_prob'); // %
  if (rec != null) {
    const penalty = -Math.round((rec / 100) * 20);
    add(penalty, '衰退機率', `模型估 ${rec.toFixed(1)}% 未來一年衰退`);
  }

  // 3) 通膨是否接近 2% 目標（用 CPI 年增）
  const cpi = val(cards, 'cpi');
  if (cpi != null) {
    if (cpi <= 2.5) add(10, '通膨', `CPI ${cpi.toFixed(1)}% 接近目標`);
    else if (cpi <= 3.5) add(3, '通膨', `CPI ${cpi.toFixed(1)}% 略高於目標`);
    else if (cpi <= 4.5) add(-6, '通膨', `CPI ${cpi.toFixed(1)}% 偏高`);
    else add(-12, '通膨', `CPI ${cpi.toFixed(1)}% 過高`);
  }

  // 4) 失業率趨勢
  const unemp = val(cards, 'unemployment');
  const unempDir = dir(cards, 'unemployment');
  if (unempDir) {
    if (unempDir === 'up') add(-8, '就業', '失業率上升，勞動市場降溫');
    else add(5, '就業', '失業率持平或下降');
  }
  if (unemp != null && unemp > 5) add(-3, '就業', `失業率 ${unemp.toFixed(1)}% 偏高`);

  // 5) 信用利差（金融壓力）
  const hy = val(cards, 'credit_spread'); // bp
  if (hy != null) {
    if (hy < 350) add(8, '信用利差', `${Math.round(hy)}bp 偏窄，風險偏好佳`);
    else if (hy < 500) add(0, '信用利差', `${Math.round(hy)}bp 中性`);
    else if (hy < 700) add(-8, '信用利差', `${Math.round(hy)}bp 擴大`);
    else add(-15, '信用利差', `${Math.round(hy)}bp 大幅擴大，信用緊縮`);
  }

  // 6) 金融條件（NFCI：正值=偏緊）
  const nfci = val(cards, 'fin_cond');
  if (nfci != null) {
    if (nfci < 0) add(8, '金融條件', `NFCI ${nfci.toFixed(2)}（偏寬鬆）`);
    else if (nfci < 0.2) add(0, '金融條件', `NFCI ${nfci.toFixed(2)}（中性）`);
    else add(-8, '金融條件', `NFCI ${nfci.toFixed(2)}（偏緊）`);
  }

  // 7) 製造業景氣（Philly Fed，>0 擴張）
  const mfg = val(cards, 'mfg');
  if (mfg != null) {
    if (mfg > 0) add(6, '製造業', `指數 ${mfg.toFixed(1)}（擴張）`);
    else add(-6, '製造業', `指數 ${mfg.toFixed(1)}（收縮）`);
  }

  // 8) 經濟成長（實質 GDP 年增）
  const gdp = val(cards, 'gdp');
  if (gdp != null) {
    if (gdp > 2.5) add(8, '成長', `GDP 年增 ${gdp.toFixed(1)}%（穩健）`);
    else if (gdp > 1) add(3, '成長', `GDP 年增 ${gdp.toFixed(1)}%（溫和）`);
    else if (gdp > 0) add(0, '成長', `GDP 年增 ${gdp.toFixed(1)}%（停滯）`);
    else add(-10, '成長', `GDP 年增 ${gdp.toFixed(1)}%（萎縮）`);
  }

  // 9) 市場波動（VIX）
  const vix = val(cards, 'vix');
  if (vix != null) {
    if (vix < 16) add(4, '波動率', `VIX ${vix.toFixed(1)}（平靜）`);
    else if (vix < 22) add(0, '波動率', `VIX ${vix.toFixed(1)}（正常）`);
    else if (vix < 30) add(-5, '波動率', `VIX ${vix.toFixed(1)}（升高）`);
    else add(-10, '波動率', `VIX ${vix.toFixed(1)}（恐慌）`);
  }

  score = Math.round(clamp(score, 0, 100));

  // 景氣 regime
  let regime;
  if (score >= 65) regime = { label: '景氣穩健 ✓', colorKey: 'green' };
  else if (score >= 50) regime = { label: '溫和成長', colorKey: 'yellow' };
  else if (score >= 35) regime = { label: '景氣放緩 ⚠', colorKey: 'yellow' };
  else regime = { label: '衰退風險高 ⚠', colorKey: 'red' };

  return { score, regime, breakdown, signals: computeSignals(cards) };
}

// ─── 五個訊號燈（陳述客觀狀態，不只看分數）───
function computeSignals(cards) {
  const signals = [];

  const spread = val(cards, 'yield_spread');
  signals.push(spread == null ? pill('殖利率曲線', '—', 'text2')
    : spread < 0 ? pill('殖利率曲線', '倒掛', 'red')
    : spread < 30 ? pill('殖利率曲線', '偏平', 'yellow')
    : pill('殖利率曲線', '正常', 'green'));

  const cpiDir = dir(cards, 'cpi');
  signals.push(cpiDir == null ? pill('通膨趨勢', '—', 'text2')
    : cpiDir === 'down' ? pill('通膨趨勢', '降溫中', 'green')
    : cpiDir === 'up' ? pill('通膨趨勢', '升溫', 'red')
    : pill('通膨趨勢', '持平', 'yellow'));

  const unempDir = dir(cards, 'unemployment');
  signals.push(unempDir == null ? pill('就業市場', '—', 'text2')
    : unempDir === 'up' ? pill('就業市場', '降溫中', 'yellow')
    : unempDir === 'down' ? pill('就業市場', '強勁', 'green')
    : pill('就業市場', '穩定', 'green'));

  const nfci = val(cards, 'fin_cond');
  signals.push(nfci == null ? pill('金融條件', '—', 'text2')
    : nfci < 0 ? pill('金融條件', '偏寬', 'green')
    : nfci < 0.2 ? pill('金融條件', '中性', 'yellow')
    : pill('金融條件', '偏緊', 'orange'));

  const gdp = val(cards, 'gdp');
  const mfg = val(cards, 'mfg');
  const rec = val(cards, 'recession_prob');
  let momentum;
  if (gdp == null && mfg == null) momentum = pill('景氣動能', '—', 'text2');
  else if ((rec != null && rec > 35) || (mfg != null && mfg < 0 && gdp != null && gdp < 1)) momentum = pill('景氣動能', '放緩', 'red');
  else if (gdp != null && gdp > 2 && (mfg == null || mfg > 0)) momentum = pill('景氣動能', '擴張', 'green');
  else momentum = pill('景氣動能', '溫和', 'yellow');
  signals.push(momentum);

  return signals;
}

function pill(label, value, colorKey) {
  return { label, value, colorKey };
}
