// terminal-data.jsx — Deterministic mock data for the TradeXchange Terminal.
// Everything is seeded from the existing seed-lattice so the numbers stay
// stable across renders and per-tab navigations.

// ── Palette shortcut (matches QP tokens) ─────────────────────
const TM = {
  bg:         '#06070A',
  surface:    '#0e1014',
  surfaceHi:  '#171a20',
  border:     'rgba(244,244,240,0.10)',
  borderHi:   'rgba(244,244,240,0.22)',
  text:       '#F4F4F0',
  textDim:    'rgba(244,244,240,0.78)',
  muted:      'rgba(244,244,240,0.55)',
  mutedDim:   'rgba(244,244,240,0.30)',
  green:      '#42f977',
  greenSoft:  'rgba(66,249,119,0.10)',
  red:        '#FF5675',
  redSoft:    'rgba(255,86,117,0.10)',
  cyan:       '#23c8e9',
  cyanSoft:   'rgba(35,200,233,0.10)',
  amber:      '#a59523',
  orange:     '#FF6A1A',
  orangeSoft: 'rgba(255,106,26,0.12)',
  violet:     '#a334f3',
  ink:        '#0A0B0E',
};

const GE = 'Geist, system-ui, sans-serif';
const GM = '"Geist Mono", ui-monospace, monospace';

// ── Seeded RNG helpers ────────────────────────────────────────
function tmRng(seed) {
  let n = (seed >>> 0) || 1;
  return () => { n = (Math.imul(n, 1664525) + 1013904223) >>> 0; return n / 0xFFFFFFFF; };
}
function tmHash(s) {
  let h = 2166136261 >>> 0;
  for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); }
  return h >>> 0;
}

// ── Market categories (templated from the Markets Overview screen) ──
const MARKET_CATEGORIES = [
  {
    key: 'stocks', label: 'Stocks',
    items: [
      { sym: 'AAPL', name: 'Apple Inc.',          base: 205.42 },
      { sym: 'NVDA', name: 'NVIDIA',              base: 1147.88 },
      { sym: 'TSLA', name: 'Tesla',               base: 287.10 },
    ],
  },
  {
    key: 'commodities', label: 'Commodities',
    items: [
      { sym: 'WTI',   name: 'Crude Oil',  base: 78.40, unit: '/ bbl' },
      { sym: 'GOLD',  name: 'Gold',       base: 2410.20, unit: '/ oz' },
      { sym: 'SILV',  name: 'Silver',     base: 28.95, unit: '/ oz' },
    ],
  },
  {
    key: 'forex', label: 'Forex',
    items: [
      { sym: 'DXY',     name: 'USD Index',  base: 102.18 },
      { sym: 'XAU/USD', name: 'XAU/USD',    base: 2410.50 },
      { sym: 'EUR/USD', name: 'EUR/USD',    base: 1.0917 },
    ],
  },
  {
    key: 'bonds', label: 'Bonds',
    items: [
      { sym: 'US2Y',  name: '2-Year',  base: 4.18, unit: '%' },
      { sym: 'US5Y',  name: '5-Year',  base: 4.32, unit: '%' },
      { sym: 'US10Y', name: '10-Year', base: 4.41, unit: '%' },
    ],
  },
  {
    key: 'crypto', label: 'Crypto',
    items: [
      { sym: 'BTC', name: 'Bitcoin',  base: 62400 },
      { sym: 'ETH', name: 'Ethereum', base: 3120 },
      { sym: 'SOL', name: 'Solana',   base: 168.40 },
    ],
  },
  {
    key: 'etfs', label: 'ETFs',
    items: [
      { sym: 'SPY', name: 'S&P 500',          base: 558.20 },
      { sym: 'QQQ', name: 'Nasdaq 100',       base: 482.10 },
      { sym: 'IWM', name: 'Russell 2000',     base: 218.40 },
    ],
  },
];

// Each tile gets a deterministic delta + 32-point sparkline.
function marketTileFor(sym) {
  const r = tmRng(tmHash('mkt:' + sym));
  const items = [].concat(...MARKET_CATEGORIES.map(c => c.items));
  const def = items.find(i => i.sym === sym) || { sym, name: sym, base: 100 };
  const pct = (r() - 0.5) * 4;             // -2% .. +2%
  const price = +(def.base * (1 + pct / 100)).toFixed(def.base < 10 ? 4 : 2);
  const up = pct >= 0;
  // 32-point sparkline trending toward final
  const spark = [];
  let v = def.base * (1 - pct / 100 * 0.4);
  for (let i = 0; i < 32; i++) {
    v += (price - v) * 0.05 + (r() - 0.5) * def.base * 0.005;
    spark.push(v);
  }
  return {
    ...def, price, pct,
    delta: +(price - def.base).toFixed(def.base < 10 ? 4 : 2),
    up, spark,
  };
}

// ── Holdings (Portfolio) ──────────────────────────────────────
const HOLDINGS = [
  { sym: 'AAPL', shares: 32,  cost: 198.50 },
  { sym: 'NVDA', shares: 8,   cost: 1024.15 },
  { sym: 'BTC',  shares: 0.5, cost: 58200 },
  { sym: 'ETH',  shares: 2.4, cost: 2960 },
  { sym: 'SPY',  shares: 14,  cost: 524.40 },
  { sym: 'GOLD', shares: 12,  cost: 2305 },
];

function holdingFor(sym) {
  const h = HOLDINGS.find(x => x.sym === sym);
  if (!h) return null;
  const m = marketTileFor(sym);
  const value = +(h.shares * m.price).toFixed(2);
  const costBasis = +(h.shares * h.cost).toFixed(2);
  const pnl = +(value - costBasis).toFixed(2);
  const pnlPct = +(((m.price - h.cost) / h.cost) * 100).toFixed(2);
  return { ...h, ...m, value, costBasis, pnl, pnlPct };
}

function allHoldings() { return HOLDINGS.map(h => holdingFor(h.sym)); }

// ── Watchlist (curated list of tickers) ──────────────────────
const WATCHLIST_TICKERS = ['AAPL', 'NVDA', 'TSLA', 'BTC', 'ETH', 'SOL', 'SPY', 'QQQ', 'GOLD', 'WTI'];
function watchlistRows() { return WATCHLIST_TICKERS.map(s => marketTileFor(s)); }

// ── Daily P/L calendar (Portfolio) ───────────────────────────
// One month of trading days. Each day's $ and % comes from the order-feed
// outcomes + a tiny mock holding-mark-to-market delta.
function pnlCalendar(year, month /* 1-12 */) {
  const start = new Date(Date.UTC(year, month - 1, 1));
  const daysIn = new Date(Date.UTC(year, month, 0)).getUTCDate();
  const out = [];
  for (let d = 1; d <= daysIn; d++) {
    const date = new Date(Date.UTC(year, month - 1, d));
    const dow = date.getUTCDay();
    // Weekends are zero
    const r = tmRng(tmHash(`pnl:${year}:${month}:${d}`));
    if (dow === 0 || dow === 6) {
      out.push({ d, date, dollars: 0, pct: 0, isWeekend: true });
      continue;
    }
    // Skew to a few big positive days and rare big negatives
    const sign = r() > 0.40 ? 1 : -1;
    const magnitude = Math.pow(r(), 2) * (sign > 0 ? 620 : 380);
    const dollars = +(sign * magnitude).toFixed(2);
    const accountBase = 18000;
    const pct = +((dollars / accountBase) * 100).toFixed(2);
    out.push({ d, date, dollars, pct, isWeekend: false });
  }
  return out;
}

function pnlMonthSummary(days) {
  const sum = days.reduce((s, x) => s + x.dollars, 0);
  const startNAV = 22518.40;
  return { dollars: +sum.toFixed(2), pct: +((sum / startNAV) * 100).toFixed(2), startNAV };
}

// ── Receipts (per-trade) — seeded ────────────────────────────
// Deterministic list of recent trades. Each has a compute_proof + base block.
function recentReceipts(count = 18) {
  const out = [];
  const syms = ['AAPL', 'NVDA', 'TSLA', 'BTC', 'ETH', 'SPY', 'GOLD'];
  const startBlock = 46270900;
  for (let i = 0; i < count; i++) {
    const r = tmRng(tmHash('rcpt:' + i));
    const sym = syms[Math.floor(r() * syms.length)];
    const side = r() > 0.5 ? 'BUY' : 'SELL';
    const cleared = r() > 0.18;
    const qty = sym === 'BTC' || sym === 'ETH' ? +(r() * 2).toFixed(2) : Math.floor(r() * 30) + 1;
    const m = marketTileFor(sym);
    const price = +(m.price * (1 + (r() - 0.5) * 0.001)).toFixed(2);
    const value = +(qty * price).toFixed(2);
    const yesVotes = cleared ? 17 + Math.floor(r() * 8) : Math.floor(r() * 17);
    const blocks = startBlock - i * 7 - Math.floor(r() * 4);
    const proof = (((tmHash('p:' + i)) >>> 0).toString(16).padStart(8, '0').slice(0, 8));
    const hour = 9 + Math.floor(r() * 7);
    const min  = Math.floor(r() * 60);
    out.push({
      i, sym, side, qty, price, value, cleared,
      yesVotes, block: blocks, proof,
      latencyMs: 120 + Math.floor(r() * 180),
      computeMs: 70 + Math.floor(r() * 60),
      time: `${String(hour).padStart(2,'0')}:${String(min).padStart(2,'0')}`,
      ts: Date.UTC(2026, 4, 21, hour, min, 0) - i * 86400000 * (Math.floor(r() * 3) + 1),
    });
  }
  return out;
}

// ── Mini sparkline component (for market tiles) ─────────────
function MiniSpark({ data, color, height = 36, width = '100%' }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const norm = data.map((v, i) => ({
    x: (i / (data.length - 1)) * 100,
    y: 100 - ((v - min) / range) * 100,
  }));
  const path = 'M ' + norm.map(p => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(' L ');
  const areaPath = path + ` L 100,100 L 0,100 Z`;
  const id = `spark-${Math.random().toString(36).slice(2, 8)}`;
  return (
    <svg width={width} height={height} viewBox="0 0 100 100" preserveAspectRatio="none"
         style={{ display: 'block' }}>
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%"   stopColor={color} stopOpacity="0.32"/>
          <stop offset="100%" stopColor={color} stopOpacity="0"/>
        </linearGradient>
      </defs>
      <path d={areaPath} fill={`url(#${id})`}/>
      <path d={path} fill="none" stroke={color} strokeWidth="1.4"
            vectorEffect="non-scaling-stroke" strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}

// ── Larger multi-line chart (used in Holding Detail) ────────
// Renders 2-3 series with shared X-axis 0..100.
function MultiLineChart({ series, height = 200, yLabels = true }) {
  if (!series || !series.length) return null;
  const all = [].concat(...series.map(s => s.data));
  const min = Math.min(...all), max = Math.max(...all);
  const range = max - min || 1;
  const norm = (v) => 100 - ((v - min) / range) * 100;
  const pad = { l: 38, r: 8, t: 12, b: 18 };

  return (
    <svg width="100%" height={height + pad.t + pad.b}
         viewBox={`0 0 100 ${100 + (pad.b / height) * 100 * 0 + 0}`}
         preserveAspectRatio="none"
         style={{ display: 'block', overflow: 'visible' }}>
      {yLabels && [0, 0.25, 0.5, 0.75, 1].map((p, i) => (
        <text key={i} x="-2" y={p * 100 + 1.5} fontSize="3"
              fill={TM.mutedDim} textAnchor="end"
              style={{ fontFamily: GM, letterSpacing: 0.4 }}>
          {(min + (1 - p) * range).toFixed(min < 10 ? 2 : 0)}
        </text>
      ))}
      {[0, 0.25, 0.5, 0.75, 1].map(p => (
        <line key={'g' + p} x1="0" x2="100" y1={p * 100} y2={p * 100}
              stroke={TM.border} strokeWidth="0.25"
              vectorEffect="non-scaling-stroke"/>
      ))}
      {series.map((s, i) => {
        const d = 'M ' + s.data.map((v, j) =>
          `${(j / (s.data.length - 1)) * 100},${norm(v).toFixed(2)}`).join(' L ');
        return <path key={i} d={d} stroke={s.color} strokeWidth="0.7" fill="none"
                     vectorEffect="non-scaling-stroke" strokeLinejoin="round"/>;
      })}
    </svg>
  );
}

// Deterministic price series for the holding detail chart.
// Returns 60 points trending from `from` to `to`.
function priceSeries(seed, from, to, points = 60, jitterPct = 0.015) {
  const r = tmRng(seed);
  const arr = [];
  for (let i = 0; i < points; i++) {
    const t = i / (points - 1);
    const linear = from + (to - from) * t;
    const noise = (r() - 0.5) * linear * jitterPct * (1 + Math.sin(t * 7) * 0.5);
    arr.push(linear + noise);
  }
  return arr;
}

Object.assign(window, {
  TM, GE, GM,
  MARKET_CATEGORIES, marketTileFor,
  HOLDINGS, holdingFor, allHoldings,
  WATCHLIST_TICKERS, watchlistRows,
  pnlCalendar, pnlMonthSummary,
  recentReceipts,
  MiniSpark, MultiLineChart, priceSeries,
  tmHash, tmRng,
});
