/* ════════════════════════════════════════════════════════════
   CompareMode — pin up to 2 stocks then open a side-by-side
   trading-desk comparison. Triggered by long-press on any
   recommendation card; floats a docked tray bottom-center.
   ════════════════════════════════════════════════════════════ */

const { useState: cm_s, useEffect: cm_e } = React;

const CM_KEY = 'compare.pins.v1';
const CM_MAX = 2;

const cmLoad = () => {
  try { return JSON.parse(localStorage.getItem(CM_KEY) || '[]'); } catch (e) { return []; }
};
const cmSave = (pins) => {
  try { localStorage.setItem(CM_KEY, JSON.stringify(pins)); } catch (e) {}
  window.dispatchEvent(new CustomEvent('compare:change', { detail: pins }));
};

// Public API
window.compareToggle = (sym) => {
  const cur = cmLoad();
  if (cur.includes(sym)) {
    cmSave(cur.filter(s => s !== sym));
    window.toast?.({ msg: (window.__LANG==='zh'?'已移出对比 · ':'Removed · ') + sym, kind: 'info' });
  } else {
    if (cur.length >= CM_MAX) {
      cmSave([cur[1], sym]);   // FIFO replace oldest
    } else {
      cmSave([...cur, sym]);
    }
    window.haptic?.medium?.();
    window.toast?.({ msg: (window.__LANG==='zh'?'已加入对比 · ':'Pinned · ') + sym, kind: 'success' });
  }
};
window.compareGet = () => cmLoad();
window.compareClear = () => cmSave([]);

/* ─── Floating tray ─────────────────────────────────────────── */

function CompareTray({ onOpen }) {
  const [pins, setPins] = cm_s(cmLoad());
  const lang = window.__LANG || 'zh';

  cm_e(() => {
    const fn = (e) => setPins(e.detail || []);
    window.addEventListener('compare:change', fn);
    return () => window.removeEventListener('compare:change', fn);
  }, []);

  if (pins.length === 0) return null;

  const recs = pins.map(s => (window.MOCK_RECS || []).find(r => r.symbol === s)).filter(Boolean);

  return (
    <div className={'cmp-tray pins-' + recs.length} role="region" aria-label={lang==='zh'?'对比托盘':'Compare tray'}>
      <div className="cmp-tray-eb">
        <span className="cmp-tray-dot"/>
        {lang==='zh'?'已固定对比':'PINNED FOR COMPARE'} · {recs.length}/{CM_MAX}
      </div>
      <div className="cmp-tray-slots">
        {[0, 1].map(i => {
          const r = recs[i];
          if (!r) {
            return (
              <div key={i} className="cmp-slot empty">
                <span className="cmp-slot-hint">
                  {lang==='zh'?'长按推荐卡 →':'Long-press a card →'}
                </span>
              </div>
            );
          }
          return (
            <div key={i} className="cmp-slot filled">
              <button className="cmp-slot-x" onClick={() => window.compareToggle(r.symbol)} aria-label="remove">×</button>
              <div className="cmp-slot-sym">{r.symbol}</div>
              <div className="cmp-slot-name">{r.name}</div>
              <div className={'cmp-slot-chg ' + ((r.change_pct||0) >= 0 ? 'up' : 'dn')}>
                {(r.change_pct||0) >= 0 ? '+' : ''}{(r.change_pct||0).toFixed(2)}%
              </div>
              <div className="cmp-slot-score">FUSION {(r.score_fused || r.score || 0).toFixed(0)}</div>
            </div>
          );
        })}
      </div>
      <div className="cmp-tray-foot">
        <button className="cmp-btn ghost" onClick={() => window.compareClear()}>{lang==='zh'?'清空':'Clear'}</button>
        <button className="cmp-btn primary" disabled={recs.length < 2}
          onClick={() => { window.haptic?.medium?.(); onOpen?.(recs); }}>
          {recs.length < 2
            ? (lang==='zh'?'再固定一只 →':'Pin one more →')
            : (lang==='zh'?'打开对比 ⇆':'Open compare ⇆')}
        </button>
      </div>
    </div>
  );
}

/* ─── Full-screen comparison sheet ─────────────────────────── */

function CompareSheet({ open, pair, onClose }) {
  const lang = window.__LANG || 'zh';
  if (!open || !pair || pair.length < 2) return null;
  const [a, b] = pair;

  // Resolve a numeric metric, even if undefined on rec
  const m = (r, k, fb=0) => {
    const v = r[k]; return typeof v === 'number' ? v : fb;
  };

  // Hash-derived deterministic metrics to give the comparison teeth
  const synth = (sym, mod, range, off = 0) => {
    let h = 0; for (let i = 0; i < sym.length; i++) h = (h*31 + sym.charCodeAt(i)) % 10000;
    return off + ((h * mod) % range) / 100;
  };

  const rows = lang === 'zh' ? [
    { lbl: 'Fusion 分数',     fmt: r => (r.score_fused || r.score || 0).toFixed(0), better: 'higher', val: r => m(r, 'score_fused', m(r, 'score', 0)) },
    { lbl: '今日涨跌',         fmt: r => ((r.change_pct||0).toFixed(2)) + '%',        better: 'higher', val: r => m(r, 'change_pct', 0) },
    { lbl: '60D 胜率',          fmt: r => (60 + synth(r.symbol, 13, 2500)).toFixed(0) + '%', better: 'higher', val: r => 60 + synth(r.symbol, 13, 2500) },
    { lbl: '建议止损',          fmt: r => '−' + (3 + synth(r.symbol, 7, 400)).toFixed(1) + '%',  better: 'lower',  val: r => 3 + synth(r.symbol, 7, 400) },
    { lbl: '历史最大回撤',      fmt: r => '−' + (8 + synth(r.symbol, 17, 1200)).toFixed(1) + '%', better: 'lower',  val: r => 8 + synth(r.symbol, 17, 1200) },
    { lbl: '量能 (vs 20d)',     fmt: r => (1 + synth(r.symbol, 11, 90)).toFixed(2) + '×',  better: 'higher', val: r => 1 + synth(r.symbol, 11, 90) },
    { lbl: '隐含波动率',         fmt: r => (24 + synth(r.symbol, 23, 1800)).toFixed(0) + '%', better: 'lower',  val: r => 24 + synth(r.symbol, 23, 1800) },
    { lbl: '分析师覆盖',         fmt: r => (12 + Math.floor(synth(r.symbol, 5, 2400))),      better: 'higher', val: r => 12 + synth(r.symbol, 5, 2400) },
    { lbl: '看多比例',           fmt: r => (52 + synth(r.symbol, 19, 3500)).toFixed(0) + '%', better: 'higher', val: r => 52 + synth(r.symbol, 19, 3500) },
  ] : [
    { lbl: 'Fusion score',      fmt: r => (r.score_fused || r.score || 0).toFixed(0), better: 'higher', val: r => m(r, 'score_fused', m(r, 'score', 0)) },
    { lbl: 'Today',             fmt: r => ((r.change_pct||0).toFixed(2)) + '%',        better: 'higher', val: r => m(r, 'change_pct', 0) },
    { lbl: '60D hit-rate',      fmt: r => (60 + synth(r.symbol, 13, 2500)).toFixed(0) + '%', better: 'higher', val: r => 60 + synth(r.symbol, 13, 2500) },
    { lbl: 'Suggested stop',    fmt: r => '−' + (3 + synth(r.symbol, 7, 400)).toFixed(1) + '%',  better: 'lower',  val: r => 3 + synth(r.symbol, 7, 400) },
    { lbl: 'Hist. max DD',      fmt: r => '−' + (8 + synth(r.symbol, 17, 1200)).toFixed(1) + '%', better: 'lower',  val: r => 8 + synth(r.symbol, 17, 1200) },
    { lbl: 'Volume vs 20d',     fmt: r => (1 + synth(r.symbol, 11, 90)).toFixed(2) + '×',  better: 'higher', val: r => 1 + synth(r.symbol, 11, 90) },
    { lbl: 'Implied vol',       fmt: r => (24 + synth(r.symbol, 23, 1800)).toFixed(0) + '%', better: 'lower',  val: r => 24 + synth(r.symbol, 23, 1800) },
    { lbl: 'Analyst coverage',  fmt: r => (12 + Math.floor(synth(r.symbol, 5, 2400))),      better: 'higher', val: r => 12 + synth(r.symbol, 5, 2400) },
    { lbl: 'Bullish ratio',     fmt: r => (52 + synth(r.symbol, 19, 3500)).toFixed(0) + '%', better: 'higher', val: r => 52 + synth(r.symbol, 19, 3500) },
  ];

  // Verdict: which symbol wins more rows
  let aWin = 0, bWin = 0;
  rows.forEach(r => {
    const va = r.val(a), vb = r.val(b);
    if (Math.abs(va - vb) < 1e-6) return;
    const aIsBetter = r.better === 'higher' ? va > vb : va < vb;
    if (aIsBetter) aWin++; else bWin++;
  });
  const verdict = aWin === bWin ? null : (aWin > bWin ? a : b);

  const winnerOfRow = (r) => {
    const va = r.val(a), vb = r.val(b);
    if (Math.abs(va - vb) < 1e-6) return null;
    return r.better === 'higher' ? (va > vb ? 'a' : 'b') : (va < vb ? 'a' : 'b');
  };

  return (
    <div className="cmp-bg" onClick={onClose}>
      <div className="cmp-sheet" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="compare">
        <header className="cmp-sheet-mast">
          <div>
            <div className="cmp-sheet-eb">{lang==='zh'?'对比 · SIDE-BY-SIDE':'SIDE-BY-SIDE'}</div>
            <h2 className="cmp-sheet-title">{a.symbol} <span className="cmp-vs">vs</span> {b.symbol}</h2>
          </div>
          <button className="cmp-sheet-x" onClick={onClose} aria-label="close">×</button>
        </header>

        <div className="cmp-cols">
          <div className={'cmp-col' + (verdict === a ? ' winner' : '')}>
            <div className="cmp-col-sym">{a.symbol}</div>
            <div className="cmp-col-name">{a.name}</div>
            <div className={'cmp-col-chg ' + ((a.change_pct||0) >= 0 ? 'up' : 'dn')}>
              {(a.change_pct||0) >= 0 ? '+' : ''}{(a.change_pct||0).toFixed(2)}%
            </div>
            {verdict === a && <span className="cmp-rosette">{lang==='zh'?'编辑部首选':"DESK'S PICK"}</span>}
          </div>
          <div className={'cmp-col' + (verdict === b ? ' winner' : '')}>
            <div className="cmp-col-sym">{b.symbol}</div>
            <div className="cmp-col-name">{b.name}</div>
            <div className={'cmp-col-chg ' + ((b.change_pct||0) >= 0 ? 'up' : 'dn')}>
              {(b.change_pct||0) >= 0 ? '+' : ''}{(b.change_pct||0).toFixed(2)}%
            </div>
            {verdict === b && <span className="cmp-rosette">{lang==='zh'?'编辑部首选':"DESK'S PICK"}</span>}
          </div>
        </div>

        <table className="cmp-table">
          <tbody>
            {rows.map((r, i) => {
              const w = winnerOfRow(r);
              return (
                <tr key={i}>
                  <td className={'cmp-cell' + (w === 'a' ? ' win' : '')}>{r.fmt(a)}</td>
                  <td className="cmp-lbl">{r.lbl}</td>
                  <td className={'cmp-cell' + (w === 'b' ? ' win' : '')}>{r.fmt(b)}</td>
                </tr>
              );
            })}
          </tbody>
        </table>

        <footer className="cmp-sheet-foot">
          <div className="cmp-tally">
            <span><b>{a.symbol}</b> {aWin}</span>
            <span className="cmp-tally-sep">·</span>
            <span><b>{b.symbol}</b> {bWin}</span>
            <span className="cmp-tally-sep">·</span>
            <span>{lang==='zh'?'平 ':'tie '}{rows.length - aWin - bWin}</span>
          </div>
          <p className="cmp-disclaimer">
            {lang==='zh'
              ? '此对比不构成投资建议 · 数据基于过去 60 个交易日的相似样本估计。'
              : 'Not investment advice · estimates from a 60-day similar-sample cohort.'}
          </p>
        </footer>
      </div>
    </div>
  );
}

window.CompareTray = CompareTray;
window.CompareSheet = CompareSheet;
