// Iteration layer — 11 UX upgrades on union style
// Loaded AFTER union.jsx, before app.jsx

const { useState: nS, useEffect: nE, useRef: nR } = React;

// ── Persistent state (localStorage) ───────────────────────────
const LS = {
  get: (k, d) => { try { return JSON.parse(localStorage.getItem('felix.' + k)) ?? d; } catch { return d; } },
  set: (k, v) => { try { localStorage.setItem('felix.' + k, JSON.stringify(v)); } catch {} },
};

// Reading state machine: unseen → seen → opened → signed
function useReadState(symbol) {
  const [state, setState] = nS(() => LS.get('rs.' + symbol, 'unseen'));
  const upgrade = (next) => {
    const order = ['unseen','seen','opened','signed'];
    if (order.indexOf(next) > order.indexOf(state)) {
      LS.set('rs.' + symbol, next); setState(next);
    }
  };
  return [state, upgrade];
}

// ── Haptic + audio feedback ───────────────────────────────────
let __actx;
const haptic = (pattern = 8) => { try { navigator.vibrate?.(pattern); } catch {} };
const beep = (freq = 440, dur = 0.06, type = 'sine', gain = 0.05) => {
  try {
    __actx = __actx || new (window.AudioContext || window.webkitAudioContext)();
    const o = __actx.createOscillator(); const g = __actx.createGain();
    o.type = type; o.frequency.value = freq;
    g.gain.setValueAtTime(gain, __actx.currentTime);
    g.gain.exponentialRampToValueAtTime(0.0001, __actx.currentTime + dur);
    o.connect(g); g.connect(__actx.destination);
    o.start(); o.stop(__actx.currentTime + dur);
  } catch {}
};
const stamp_sfx = () => { beep(140, 0.05, 'square', 0.08); haptic([15, 30, 10]); };
const flip_sfx  = () => { beep(620, 0.04, 'sine', 0.04); haptic(6); };

window.felix = { LS, haptic, beep, stamp_sfx, flip_sfx };

// ── Freshness decay by term ───────────────────────────────────
function decayStatus(term, minutes) {
  const thresh = { short: [15, 30], medium: [120, 360], long: [720, 1440] }[term] || [30, 120];
  if (minutes <= thresh[0]) return 'ok';
  if (minutes <= thresh[1]) return 'warn';
  return 'stale';
}
window.decayStatus = decayStatus;

// ── Chinese language polish (override at runtime) ─────────────
const ZH_POLISH = {
  '亏损概率': '下行空间',
  'loss probability': 'downside space',
};
window.polishZh = (s) => {
  const lang = window.__LANG || 'zh';
  if (lang !== 'zh') return s;
  let out = s;
  for (const k in ZH_POLISH) out = out.split(k).join(ZH_POLISH[k]);
  return out;
};

// ── Comparison vs 30d average ─────────────────────────────────
function compareScore(rec) {
  // mock: derive a stable "30d avg" from symbol hash
  let h = 0; for (let i = 0; i < rec.symbol.length; i++) h = (h*31 + rec.symbol.charCodeAt(i)) % 1000;
  const avg = 62 + (h % 18); // 62-79
  const diff = rec.scores.fusion - avg;
  return { avg, diff };
}
window.compareScore = compareScore;

// ── Causality chain panel ────────────────────────────────────
function CausalityChain({ rec }) {
  const [openIdx, setOpenIdx] = nS(null);
  const lang = window.__LANG || 'zh';
  // mock triggers from reasoning
  const triggers = lang === 'zh' ? [
    { ttl: 'MA50 上穿 MA200', detail: '5 月 8 日金叉信号触发,趋势确认。', hist: { count: 12, win: 0.75 } },
    { ttl: 'RSI 从 28 反弹至 52', detail: '超卖区脱离,动能转正。', hist: { count: 28, win: 0.61 } },
    { ttl: '北向 5 日净流入 ¥18B', detail: '外资连续加仓,与历史拐点相符。', hist: { count: 7, win: 0.71 } },
  ] : [
    { ttl: 'MA50 crossed above MA200', detail: 'Golden cross confirmed 5/8.', hist: { count: 12, win: 0.75 } },
    { ttl: 'RSI rebounded 28 → 52', detail: 'Oversold exit, momentum positive.', hist: { count: 28, win: 0.61 } },
    { ttl: 'Northbound net buy ¥18B / 5d', detail: 'Foreign accumulation matches past inflection points.', hist: { count: 7, win: 0.71 } },
  ];
  return (
    <div className="causality">
      <div className="caus-head">
        <span>{lang === 'zh' ? '因果链 · 这个分凭什么' : 'Causality · why this score'}</span>
        <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--ink-3)', fontSize: 10 }}>n = 3</span>
      </div>
      {triggers.map((tr, i) => (
        <div key={i} className={'caus-row' + (openIdx === i ? ' open' : '')}>
          <button className="caus-trigger" onClick={() => { setOpenIdx(openIdx === i ? null : i); flip_sfx(); }}>
            <span className="caus-num">{i+1}.</span>
            <span className="caus-ttl">{tr.ttl}</span>
            <span className="caus-arrow">→</span>
          </button>
          {openIdx === i && (
            <div className="caus-body">
              <div className="caus-detail">「{tr.detail}」</div>
              <div className="caus-hist">
                <span>{lang === 'zh' ? '过往 12 个月此条件出现' : 'Past 12 mo occurrence'}: <b>{tr.hist.count} {lang === 'zh' ? '次' : 'times'}</b></span>
                <span>{lang === 'zh' ? '胜率' : 'win rate'}: <b style={{ color: tr.hist.win >= 0.6 ? 'var(--up-strong)' : 'var(--accent-paper)' }}>{Math.round(tr.hist.win*100)}%</b></span>
              </div>
            </div>
          )}
        </div>
      ))}
    </div>
  );
}
window.CausalityChain = CausalityChain;

// ── Opposite analyst (bear-side counterpart) ─────────────────
function OppositeAnalyst({ rec }) {
  const lang = window.__LANG || 'zh';
  const flipScore = (s) => Math.max(20, 100 - s);
  const bearReasons = {
    NVDA: { tech: lang==='zh'?'RSI 已破 70 超买,顶背离风险。':'RSI past 70, bearish divergence risk.',
            ai: lang==='zh'?'AI capex 预期已 priced in,边际惊喜递减。':'AI capex priced in; marginal surprise decays.',
            ex: lang==='zh'?'卖方目标价上修已饱和,共识高位。':'Sell-side targets crowded at consensus highs.' },
  };
  const r = bearReasons[rec.symbol] || { tech: lang==='zh'?'技术面顶部信号未消失。':'Topping pattern still in play.',
                                          ai: lang==='zh'?'AI 模型对反向场景的解释力同样存在。':'Model can equally explain a downside scenario.',
                                          ex: lang==='zh'?'空头分析师持续给出谨慎评级。':'Bear analysts maintain caution.' };
  return (
    <div className="opposite">
      <div className="opp-head">
        <span className="opp-lab">{lang==='zh'?'对手盘 · 反方分析师':'Opposite Desk · Bear Analysts'}</span>
        <span className="opp-score">{flipScore(rec.scores.fusion)}<span style={{ fontSize: 10, color: 'var(--ink-3)' }}>/100</span></span>
      </div>
      <AnalystBubbles
        scores={{ technical: flipScore(rec.scores.technical), ai: flipScore(rec.scores.ai), expert: flipScore(rec.scores.expert) }}
        reasoning={{ technical: r.tech, ai: r.ai, expert: r.ex }}
      />
    </div>
  );
}
window.OppositeAnalyst = OppositeAnalyst;

// ── Contract follow-up (if user signed earlier) ──────────────
function ContractFollowup({ rec }) {
  const sig = LS.get('sig.' + rec.symbol, null);
  if (!sig) return null;
  const lang = window.__LANG || 'zh';
  const daysAgo = Math.max(0, Math.floor((Date.now() - sig.t) / 86400000));
  // simulate pnl since sign
  let h = 0; for (let i = 0; i < rec.symbol.length; i++) h = (h*31 + rec.symbol.charCodeAt(i)) % 1000;
  const pnl = ((h % 11) - 4) * 0.8;
  const distSL = ((rec.price.current - rec.recommendation.stop_loss) / rec.price.current * 100);
  return (
    <div className="followup">
      <div className="fu-mark">📜</div>
      <div className="fu-body">
        <div className="fu-ttl">{lang==='zh'?'§III 履约回顾':'§III Acknowledgement — followed up'}</div>
        <div className="fu-text">
          {lang==='zh'?`你于 ${new Date(sig.t).toLocaleDateString('zh-CN')} 签署 (${daysAgo} 天前)`
                     :`Signed ${new Date(sig.t).toLocaleDateString('en-US')} · ${daysAgo}d ago`}
        </div>
        <div className="fu-stats">
          <span>{lang==='zh'?'当前盈亏':'P&L'} <b style={{ color: pnl >= 0 ? 'var(--up-strong)' : 'var(--down-strong)' }}>{pnl >= 0 ? '+' : ''}{pnl.toFixed(2)}%</b></span>
          <span>{lang==='zh'?'距止损':'To SL'} <b>{distSL.toFixed(1)}%</b></span>
        </div>
      </div>
    </div>
  );
}
window.ContractFollowup = ContractFollowup;

// ── Sign action (call from contract panel button) ────────────
window.signContract = (symbol) => {
  LS.set('sig.' + symbol, { t: Date.now() });
  stamp_sfx();
};

// ── Market context continuity toast ──────────────────────────
function MarketContinuity({ market }) {
  const [prev, setPrev] = nS(() => LS.get('lastMarket', null));
  const [show, setShow] = nS(false);
  const last = nR(market);
  nE(() => {
    if (last.current !== market) {
      const prevMkt = last.current;
      const seen = LS.get('seen.' + prevMkt, []);
      if (seen.length > 0) { setPrev({ market: prevMkt, syms: seen.slice(-3) }); setShow(true); setTimeout(() => setShow(false), 4200); }
      last.current = market;
      LS.set('lastMarket', market);
    }
  }, [market]);
  if (!show || !prev || prev.market === market) return null;
  const lang = window.__LANG || 'zh';
  return (
    <div className="continuity">
      <span>{lang==='zh'?'你刚在':'Just now in'} <b>{t('dashboard.market_' + prev.market)}</b> {lang==='zh'?'看了':'you saw'}</span>
      <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--accent-paper)' }}>{prev.syms.join(' · ')}</span>
    </div>
  );
}
window.MarketContinuity = MarketContinuity;
window.markSeen = (market, symbol) => {
  const k = 'seen.' + market;
  const arr = LS.get(k, []);
  if (!arr.includes(symbol)) { arr.push(symbol); LS.set(k, arr.slice(-10)); }
};

// ── Weekend / closed-market recap ────────────────────────────
function MarketClosedBanner({ market }) {
  const d = new Date();
  const dow = d.getDay();
  const closed = market === 'cn' && (dow === 0 || dow === 6);
  const closedUS = market === 'us' && (dow === 0 || dow === 6);
  if (!closed && !closedUS) return null;
  const lang = window.__LANG || 'zh';
  return (
    <div className="closed-banner">
      <div className="cb-mast">{lang==='zh'?'休市 · WEEKEND EDITION':'CLOSED · WEEKEND EDITION'}</div>
      <div className="cb-title">{lang==='zh'?'本周推荐成绩单':'The Week in Review'}</div>
      <div className="cb-stats">
        <div><span className="lab">{lang==='zh'?'本周推荐':'Picks'}</span><span className="v">14</span></div>
        <div><span className="lab">{lang==='zh'?'胜率':'Win'}</span><span className="v" style={{ color: 'var(--up-strong)' }}>71%</span></div>
        <div><span className="lab">{lang==='zh'?'最佳':'Best'}</span><span className="v" style={{ color: 'var(--up-strong)' }}>+8.2%</span></div>
        <div><span className="lab">{lang==='zh'?'最差':'Worst'}</span><span className="v" style={{ color: 'var(--down-strong)' }}>−3.4%</span></div>
      </div>
      <div className="cb-note">{lang==='zh'?'周一开盘前可再查看 · 周末数据不更新':'Re-check before Monday open · weekend data frozen'}</div>
    </div>
  );
}
window.MarketClosedBanner = MarketClosedBanner;

// ── Term-aware PulseDot ───────────────────────────────────────
function TermPulse({ term, minutes }) {
  const status = decayStatus(term, minutes);
  return <PulseDot status={status} />;
}
window.TermPulse = TermPulse;
