/* src/v2/macro.jsx — MacroRow: yield curve, credit & vol, inflation, sector leaderboard.
   Each card self-fetches; on failure falls back to seed data from data-ext. */

const { useState: _msS, useEffect: _msE, useMemo: _msM } = React;

// ---------- Yield curve card ----------
function YieldCurveCard() {
  const [curve, setCurve] = _msS(YIELD_CURVE_SEED);
  const [loading, setLoading] = _msS(true);

  _msE(() => {
    let alive = true;
    (async () => {
      try {
        const data = await window.TMT_API.getJSON('/treasury-yields');
        if (!alive || !data || !data.yields) return;
        const order = ['1M', '3M', '6M', '1Y', '2Y', '5Y', '10Y', '30Y'];
        const next = order
          .filter(k => data.yields[k] && data.yields[k].value != null)
          .map(k => ({ tenor: k, label: k, y: Number(data.yields[k].value) }));
        if (next.length >= 4) setCurve(next);
      } catch (e) { /* keep seed */ }
      finally { if (alive) setLoading(false); }
    })();
    return () => { alive = false; };
  }, []);

  const y2 = curve.find(p => p.tenor === '2Y')?.y;
  const y10 = curve.find(p => p.tenor === '10Y')?.y;
  const spread = (y2 != null && y10 != null) ? (y10 - y2) * 100 : null; // bps
  const label = spread == null ? '' : (spread > 10 ? 'steepening' : spread < -10 ? 'inverted' : 'flat');
  const stClass = spread == null ? '' : (spread > 0 ? 'up' : 'down');

  const mn = Math.min(...curve.map(p => p.y));
  const mx = Math.max(...curve.map(p => p.y));
  const rng = (mx - mn) || 0.01;

  return (
    <div className="macro">
      <div className="hd">
        <span className="t">Yield curve</span>
        {label && <span className={'st ' + stClass}>{label}</span>}
      </div>
      <div className="big">{y10 != null ? y10.toFixed(2) + '%' : '—'}</div>
      <div className="chg">
        10Y · {spread != null ? (spread >= 0 ? '+' : '') + spread.toFixed(0) + 'bps 2s10s' : ''}
      </div>
      <div className="viz">
        <svg viewBox="0 0 200 44" preserveAspectRatio="none" style={{ width: '100%', height: 44 }}>
          {(() => {
            const step = 200 / (curve.length - 1);
            const pts = curve.map((p, i) => ({
              x: i * step,
              y: 40 - ((p.y - mn) / rng) * 34,
              v: p
            }));
            const path = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p.x.toFixed(1) + ',' + p.y.toFixed(1)).join(' ');
            return (
              <>
                <path d={path} fill="none" stroke="var(--warm)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                {pts.map((p, i) => <circle key={i} cx={p.x} cy={p.y} r="1.8" fill="var(--warm)" />)}
              </>
            );
          })()}
        </svg>
      </div>
      <div className="explain">{loading ? 'Loading…' : curve.map(p => p.tenor + ' ' + p.y.toFixed(2)).slice(0, 4).join(' · ')}</div>
    </div>
  );
}

// ---------- Credit + Vol card ----------
function CreditVolCard() {
  const [oas, setOas] = _msS(HY_OAS_SEED);
  const [vixSeries, setVixSeries] = _msS(VIX_SEED);

  _msE(() => {
    let alive = true;
    (async () => {
      try {
        const data = await window.TMT_API.getJSON('/fred?series=BAMLH0A0HYM2,VIXCLS&range=1y');
        if (!alive || !data || !data.data) return;
        const hy = data.data.BAMLH0A0HYM2;
        const vix = data.data.VIXCLS;
        if (Array.isArray(hy) && hy.length >= 4) {
          setOas(hy.map(p => Number(p.value)).filter(v => !isNaN(v)).slice(-30));
        }
        if (Array.isArray(vix) && vix.length >= 4) {
          setVixSeries(vix.map(p => Number(p.value)).filter(v => !isNaN(v)).slice(-30));
        }
      } catch (e) { /* keep seed */ }
    })();
    return () => { alive = false; };
  }, []);

  const lastOas = oas[oas.length - 1];
  const firstOas = oas[0];
  const trend = lastOas < firstOas ? 'tightening' : lastOas > firstOas ? 'widening' : 'flat';
  const stClass = lastOas < firstOas ? 'up' : 'down';
  const vix = vixSeries[vixSeries.length - 1];

  return (
    <div className="macro">
      <div className="hd">
        <span className="t">Credit &amp; vol</span>
        <span className={'st ' + stClass}>{trend}</span>
      </div>
      <div className="big">{lastOas != null ? Math.round(lastOas * 100) + 'bps' : '—'}</div>
      <div className="chg">HY OAS · VIX {vix != null ? vix.toFixed(1) : '—'}</div>
      <div className="viz">
        <Spark series={oas} w={200} h={34} color="var(--cool)" fill={true} />
      </div>
      <div className="explain">High-yield option-adjusted spread vs S&amp;P 500 vol index.</div>
    </div>
  );
}

// ---------- Inflation / CPI card ----------
function InflationCard() {
  const [cpi, setCpi] = _msS(CPI_SEED);
  const [headline, setHeadline] = _msS(null);
  const [core, setCore] = _msS(null);

  _msE(() => {
    let alive = true;
    (async () => {
      try {
        const data = await window.TMT_API.getJSON('/cpi-data');
        if (!alive || !data || !data.summary) return;
        const h = data.summary.headline;
        const c = data.summary.core;
        if (h && h.current != null) setHeadline(Number(h.current));
        if (c && c.current != null) setCore(Number(c.current));
        if (h && Array.isArray(h.historical) && h.historical.length >= 4) {
          setCpi(cur => ({ ...cur, headline: h.historical.slice(-6).map(p => ({ period: p.period || p.date, value: Number(p.value) })) }));
        }
      } catch (e) { /* keep seed */ }
    })();
    return () => { alive = false; };
  }, []);

  const h = headline != null ? headline : cpi.headline[cpi.headline.length - 1].value;
  const c = core != null ? core : cpi.core[cpi.core.length - 1].value;
  const prev = cpi.headline[cpi.headline.length - 2]?.value ?? h;
  const delta = h - prev;
  const stClass = delta < 0 ? 'up' : delta > 0 ? 'down' : '';

  return (
    <div className="macro">
      <div className="hd">
        <span className="t">Inflation</span>
        <span className={'st ' + stClass}>{delta < 0 ? 'cooling' : delta > 0 ? 'sticky' : 'flat'}</span>
      </div>
      <div className="big">{h != null ? h.toFixed(1) + '%' : '—'}</div>
      <div className="chg">Headline · core {c != null ? c.toFixed(1) + '%' : '—'} YoY</div>
      <div className="viz">
        <svg viewBox="0 0 200 34" preserveAspectRatio="none" style={{ width: '100%', height: 34 }}>
          {(() => {
            const vs = cpi.headline.map(p => p.value);
            const mn = Math.min(...vs);
            const mx = Math.max(...vs);
            const rng = (mx - mn) || 1;
            const bw = 200 / vs.length - 2;
            return vs.map((v, i) => {
              const hgt = Math.max(3, ((v - mn) / rng) * 28);
              return <rect key={i} x={i * (bw + 2) + 1} y={34 - hgt - 2} width={bw} height={hgt} fill="var(--warm)" rx="1" />;
            });
          })()}
        </svg>
      </div>
      <div className="explain">Headline YoY last {cpi.headline.length} prints.</div>
    </div>
  );
}

// ---------- Sector leaderboard card (takes 3 macro-grid columns) ----------
// Timeframes map to approximate trading-day offsets on a daily-interval series.
const SECTOR_TIMEFRAMES = [
  { id: '1D',  label: '1D',  days: 1   },
  { id: '7D',  label: '7D',  days: 5   },
  { id: '1M',  label: '1M',  days: 21  },
  { id: '3M',  label: '3M',  days: 63  },
  { id: '6M',  label: '6M',  days: 126 },
  { id: '12M', label: '12M', days: 252 },
];
const SECTOR_TF_LABEL = { '1D': 'Today', '7D': 'Past 7 days', '1M': 'Past month', '3M': 'Past 3 months', '6M': 'Past 6 months', '12M': 'Past 12 months' };

function SectorLeaderboardCard() {
  const [sectors, setSectors] = _msS(() => SECTOR_ETFS.map(s => ({
    sym: s.sym, name: s.name,
    px: BY_SYM[s.sym]?.px ?? 0,
    change: { '1D': BY_SYM[s.sym]?.chPct ?? 0, '7D': null, '1M': null, '3M': null, '6M': null, '12M': null },
  })));
  const [loading, setLoading] = _msS(true);
  const [timeframe, setTimeframe] = _msS('1D');

  _msE(() => {
    let alive = true;
    (async () => {
      const syms = SECTOR_ETFS.map(s => s.sym);
      const [quotesRes, ...chartRes] = await Promise.allSettled([
        window.TMT_API.getJSON('/batch-quotes?symbols=' + syms.join(',')),
        ...syms.map(sym =>
          window.TMT_API.getJSON('/yahoo-chart?symbol=' + sym + '&range=1y&interval=1d')
        ),
      ]);
      if (!alive) return;

      const quotes = (quotesRes.status === 'fulfilled' && quotesRes.value && quotesRes.value.quotes) || [];

      const next = SECTOR_ETFS.map((s, i) => {
        const q = quotes.find(x => x.symbol === s.sym) || {};
        const chart = chartRes[i] && chartRes[i].status === 'fulfilled' ? chartRes[i].value : null;
        const result = chart && chart.chart && chart.chart.result && chart.chart.result[0];
        const closes = (result && result.indicators && result.indicators.quote && result.indicators.quote[0] && result.indicators.quote[0].close) || [];
        const clean = closes.filter(v => v != null && !isNaN(v));
        const last = clean.length ? clean[clean.length - 1] : null;

        const pctAgo = (days) => {
          if (!clean.length || last == null) return null;
          const idx = Math.max(0, clean.length - 1 - days);
          const prev = clean[idx];
          if (prev == null || prev === 0) return null;
          return ((last - prev) / prev) * 100;
        };

        const change = {};
        for (const tf of SECTOR_TIMEFRAMES) {
          if (tf.id === '1D') {
            change[tf.id] = (q.regularMarketChangePercent != null)
              ? q.regularMarketChangePercent
              : (pctAgo(1) ?? BY_SYM[s.sym]?.chPct ?? 0);
          } else {
            change[tf.id] = pctAgo(tf.days);
          }
        }

        return {
          sym: s.sym,
          name: s.name,
          px: q.regularMarketPrice ?? last ?? BY_SYM[s.sym]?.px ?? 0,
          change,
        };
      });
      setSectors(next);
      setLoading(false);
    })();
    return () => { alive = false; };
  }, []);

  const withCur = sectors.map(s => ({ ...s, cur: s.change?.[timeframe] }));
  const ranked = [...withCur].sort((a, b) => ((b.cur ?? -Infinity) - (a.cur ?? -Infinity)));
  const maxAbs = Math.max(0.3, ...ranked.map(s => Math.abs(s.cur || 0)));

  return (
    <div className="macro macro-sector">
      <div className="hd">
        <span className="t">Sector leaderboard</span>
        {loading && <span className="st">live</span>}
      </div>
      <div className="sb-tf">
        {SECTOR_TIMEFRAMES.map(tf => (
          <button
            key={tf.id}
            type="button"
            className={'sb-tf-btn' + (timeframe === tf.id ? ' on' : '')}
            onClick={() => setTimeframe(tf.id)}
          >{tf.label}</button>
        ))}
      </div>
      <div className="sector-breadth">
        <div className="sb-h">{SECTOR_TF_LABEL[timeframe]} · sorted by change</div>
        {ranked.map(s => {
          const pct = s.cur;
          if (pct == null) {
            return (
              <div className="sb-row" key={s.sym}>
                <span className="sb-n">{s.name}</span>
                <span className="sb-bar"><span style={{ width: 0 }} /></span>
                <span className="sb-nums"><span style={{ color: 'var(--ink-4)' }}>—</span></span>
              </div>
            );
          }
          const pos = pct >= 0;
          const barPct = Math.max(6, (Math.abs(pct) / maxAbs) * 100);
          return (
            <div className="sb-row" key={s.sym}>
              <span className="sb-n">{s.name}</span>
              <span className="sb-bar">
                <span className={pos ? 'g' : 'r'} style={{ width: barPct + '%' }} />
              </span>
              <span className="sb-nums">
                <span className={pos ? 'up' : 'down'}>{fmtPct(pct)}</span>
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------- MacroRow (composition) ----------
// Left: three small macro stat cards stacked vertically so each sits at its
// natural height (no dead space from grid row-equalization against sector).
// Right: sector leaderboard.
function MacroRow() {
  return (
    <div className="macro-row">
      <div className="macro-stack">
        <YieldCurveCard />
        <CreditVolCard />
        <InflationCard />
      </div>
      <SectorLeaderboardCard />
    </div>
  );
}

Object.assign(window, { MacroRow, YieldCurveCard, CreditVolCard, InflationCard, SectorLeaderboardCard });
