// Returns — simulated buy-and-hold performance of BUY recommendations plus
// analysis spend (ONC-412). Two tabs: Returns | Costs. Light-terminal look:
// dark glowing KPI band on the light app base, mono numerics throughout.
// Design decisions recorded on ONC-412 (Linear); prototype on
// proto/onc-412-returns-preview.

(function () {
  const fmtPct = v => v == null ? '—' : (v > 0 ? '+' : '') + v.toFixed(1) + '%';
  const fmtPx = v => v == null ? '—'
    : '$' + v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const posNeg = v => v == null ? 'var(--ink-500)' : (v >= 0 ? 'var(--buy)' : 'var(--pass)');

  // Simulated $1,000 into each priced position.
  const STAKE = 1000;
  const fmtMoney = v => v == null ? '—' : '$' + Math.round(v).toLocaleString('en-US');
  const fmtMoneyDelta = v => v == null ? '—' : (v >= 0 ? '+' : '−') + '$' + Math.round(Math.abs(v)).toLocaleString('en-US');
  const stakeValue = p => p.return_pct == null ? null : STAKE * (1 + p.return_pct / 100);
  const stakeTotals = positions => {
    const priced = positions.filter(p => p.return_pct != null);
    const invested = priced.length * STAKE;
    const value = priced.reduce((s, p) => s + stakeValue(p), 0);
    return { invested, value, pnl: value - invested };
  };

  const MONO = 'var(--font-mono)';

  // ── KPI card: the app's own StatCard, accent-coloured by direction ─────────
  function Kpi({ label, value, hint, tone }) {
    const accent = tone === 'up' ? 'var(--buy)' : tone === 'down' ? 'var(--pass)' : undefined;
    return <window.StatCard label={label} value={value} hint={hint} accent={accent} />;
  }

  function CardTitle({ children, right }) {
    return (
      <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink-800)',
        margin: '0 0 12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <span>{children}</span>{right}
      </div>
    );
  }

  function Card({ children, style }) {
    return <div className="card" style={{ padding: '16px 18px', marginBottom: 14, ...style }}>{children}</div>;
  }

  // ── Chart.js (UMD, pinned in index.html) with token-matched defaults ───────
  const BUY = '#00A86B', PASS = '#E5484D', SECONDARY = '#0070C0';
  const CHART_FONT = { family: "'JetBrains Mono', ui-monospace, monospace", size: 10 };

  function baseOptions(horizontal) {
    return {
      responsive: true,
      maintainAspectRatio: false,
      indexAxis: horizontal ? 'y' : 'x',
      animation: { duration: 300 },
      plugins: {
        legend: { display: false },
        tooltip: {
          backgroundColor: '#0A1628', titleFont: { ...CHART_FONT, size: 11 },
          bodyFont: CHART_FONT, padding: 10, cornerRadius: 6, displayColors: false,
        },
      },
      scales: {
        x: {
          grid: { display: !horizontal ? false : true, color: '#EEF1F6' },
          border: { display: false },
          ticks: { font: CHART_FONT, color: '#6B7A90' },
        },
        y: {
          grid: { display: horizontal ? false : true, color: '#EEF1F6' },
          border: { display: false },
          ticks: { font: CHART_FONT, color: '#6B7A90' },
        },
      },
    };
  }

  function ChartCanvas({ config, height }) {
    const { useRef, useEffect } = React;
    const canvasRef = useRef(null);
    const chartRef = useRef(null);
    const key = JSON.stringify(config.data.labels) + config.data.datasets.map(d => String(d.data)).join('|');
    useEffect(() => {
      if (!window.Chart || !canvasRef.current) return;
      chartRef.current = new window.Chart(canvasRef.current, config);
      return () => { chartRef.current?.destroy(); chartRef.current = null; };
    }, [key, height]);
    return <div style={{ position: 'relative', height }}><canvas ref={canvasRef} /></div>;
  }

  // ── Returns tab sections ───────────────────────────────────────────────────
  function ColumnChart({ items, format }) {
    // items: [{label, sub, value, display, tone}] — Chart.js vertical bars.
    const config = {
      type: 'bar',
      data: {
        labels: items.map(i => i.label),
        datasets: [{
          data: items.map(i => i.value),
          backgroundColor: items.map(i => i.tone === 'neutral' ? SECONDARY : (i.value >= 0 ? BUY : PASS)),
          borderRadius: 4, maxBarThickness: 46,
        }],
      },
      options: {
        ...baseOptions(false),
        plugins: {
          ...baseOptions(false).plugins,
          tooltip: {
            ...baseOptions(false).plugins.tooltip,
            callbacks: {
              title: its => items[its[0].dataIndex].label,
              label: it => [items[it.dataIndex].display, items[it.dataIndex].sub],
            },
          },
        },
        scales: {
          ...baseOptions(false).scales,
          y: {
            ...baseOptions(false).scales.y,
            ticks: { ...baseOptions(false).scales.y.ticks, callback: format || (v => v) },
          },
        },
      },
    };
    return <ChartCanvas config={config} height={220} />;
  }

  function Cohorts({ cohorts }) {
    if (!cohorts?.length) return null;
    return (
      <Card>
        <CardTitle>Average return by entry month</CardTitle>
        <ColumnChart format={v => v + '%'} items={cohorts.map(c => ({
          label: c.month, sub: `${c.count} positions`, value: c.avg_return_pct, display: 'Avg ' + fmtPct(c.avg_return_pct),
        }))} />
      </Card>
    );
  }

  function OutlierCard({ p, good }) {
    return (
      <div style={{
        borderLeft: `2px solid var(--${good ? 'buy' : 'pass'})`,
        border: '1px solid var(--ink-200)', borderLeftWidth: 2,
        borderLeftColor: `var(--${good ? 'buy' : 'pass'})`,
        borderRadius: '0 8px 8px 0', padding: '12px 14px', background: 'var(--paper)',
      }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
          <span style={{ fontFamily: MONO, fontWeight: 600, fontSize: 13 }}>{p.ticker}</span>
          <span style={{ fontFamily: MONO, fontSize: 16, fontWeight: 600, color: posNeg(p.return_pct) }}>{fmtPct(p.return_pct)}</span>
        </div>
        <div style={{ fontFamily: MONO, fontSize: 10.5, color: 'var(--ink-500)', margin: '2px 0 8px' }}>
          {p.company_name} · {p.entry_date}</div>
        {p.thesis && <div style={{ fontSize: 12, lineHeight: 1.55, color: 'var(--ink-700)' }}>{p.thesis}</div>}
      </div>
    );
  }

  function Outliers({ outliers }) {
    if (!outliers || (!outliers.over?.length && !outliers.under?.length)) return null;
    return (
      <div style={{ marginBottom: 14 }}>
        <CardTitle>Outliers · beyond ±1.5σ</CardTitle>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, alignItems: 'start' }}>
          <div style={{ display: 'grid', gap: 8 }}>{(outliers.over || []).map((p, i) => <OutlierCard key={i} p={p} good />)}</div>
          <div style={{ display: 'grid', gap: 8 }}>{(outliers.under || []).map((p, i) => <OutlierCard key={i} p={p} good={false} />)}</div>
        </div>
      </div>
    );
  }

  function PositionsTable({ positions }) {
    const { useState } = React;
    const [sortKey, setSortKey] = useState('return_pct');
    const [sortDir, setSortDir] = useState(-1);
    const sortBy = k => {
      if (sortKey === k) setSortDir(d => -d);
      else { setSortKey(k); setSortDir(k === 'ticker' || k === 'entry_date' ? 1 : -1); }
    };
    const rows = [...positions].sort((a, b) => {
      const x = a[sortKey], y = b[sortKey];
      if (x == null) return 1; if (y == null) return -1;
      return (x > y ? 1 : x < y ? -1 : 0) * sortDir;
    });
    const th = (label, key, num) => (
      <th onClick={key ? () => sortBy(key) : undefined} style={{
        textAlign: num ? 'right' : 'left', fontFamily: MONO, fontSize: 9, fontWeight: 600,
        letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--ink-500)',
        padding: '7px 10px', borderBottom: '1px solid var(--ink-300)',
        cursor: key ? 'pointer' : 'default', userSelect: 'none', whiteSpace: 'nowrap' }}>
        {label}{sortKey === key ? (sortDir === 1 ? ' ↑' : ' ↓') : ''}</th>
    );
    const td = { padding: '7px 10px', borderBottom: '1px solid var(--ink-150)' };
    const ccy = p => p.currency === 'CAD'
      ? <span style={{ fontSize: 8, color: 'var(--ink-400)', marginLeft: 3, fontFamily: MONO }}>CAD</span> : null;
    return (
      <Card>
        <CardTitle>Positions</CardTitle>
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
            <thead><tr>
              {th('Ticker', 'ticker')}{th('Company')}{th('Entry', 'entry_date')}
              {th('Entry px', null, true)}{th('Latest', null, true)}
              {th('Return', 'return_pct', true)}{th('$1k now', 'return_pct', true)}{th('Days', 'days_held', true)}
            </tr></thead>
            <tbody className="row-hover">
              {rows.map((p, i) => (
                <tr key={i}>
                  <td style={{ ...td, fontFamily: MONO, fontWeight: 600 }}>{p.ticker}</td>
                  <td style={{ ...td, color: 'var(--ink-600)' }}>{p.company_name}</td>
                  <td style={{ ...td, fontFamily: MONO, color: 'var(--ink-600)' }}>{p.entry_date}</td>
                  <td style={{ ...td, fontFamily: MONO, textAlign: 'right' }}>{fmtPx(p.entry_price)}{ccy(p)}</td>
                  <td style={{ ...td, fontFamily: MONO, textAlign: 'right' }}>{fmtPx(p.latest_price)}{ccy(p)}</td>
                  <td style={{ ...td, fontFamily: MONO, textAlign: 'right', fontWeight: 600, color: posNeg(p.return_pct) }}>{fmtPct(p.return_pct)}</td>
                  <td style={{ ...td, fontFamily: MONO, textAlign: 'right', color: posNeg(p.return_pct) }}>{fmtMoney(stakeValue(p))}</td>
                  <td style={{ ...td, fontFamily: MONO, textAlign: 'right', color: 'var(--ink-500)' }}>{p.days_held}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>
    );
  }

  function Foot({ children }) {
    return <div style={{ fontSize: 11.5, color: 'var(--ink-400)', margin: '12px 2px 0' }}>{children}</div>;
  }

  function RefreshBtn({ onRefresh, refreshing }) {
    return (
      <button onClick={onRefresh} disabled={refreshing} style={{
        fontSize: 12, fontWeight: 500,
        color: 'var(--ink-600)', border: '1px solid var(--ink-200)', borderRadius: 7,
        padding: '6px 12px', background: 'var(--paper)', marginLeft: 'auto',
        cursor: refreshing ? 'wait' : 'pointer', opacity: refreshing ? 0.6 : 1 }}>
        {refreshing ? '↻ Refreshing…' : '↻ Refresh prices'}</button>
    );
  }

  // Hero figure leads; one full-book diverging chart is the centerpiece.
  function Hero({ data }) {
    const A = data.aggregates;
    const up = (A.avg_return_pct ?? 0) >= 0;
    const sub = (label, value, color) => (
      <div>
        <div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-500)' }}>{label}</div>
        <div className="stat-tnum" style={{ fontFamily: MONO, fontSize: 20, fontWeight: 600, color: color || 'var(--ink-900)', marginTop: 2 }}>{value}</div>
      </div>
    );
    return (
      <div className="card" style={{ padding: '22px 26px', margin: '14px 0 14px',
        display: 'flex', alignItems: 'center', gap: 44, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-500)' }}>
            Avg simulated return</div>
          <div className="stat-tnum" style={{ fontFamily: MONO, fontSize: 52, fontWeight: 700, lineHeight: 1.1,
            letterSpacing: '-0.03em', color: up ? 'var(--buy)' : 'var(--pass)' }}>
            {fmtPct(data.aggregates.avg_return_pct)}</div>
          <div style={{ fontSize: 12, color: 'var(--ink-500)', marginTop: 2 }}>
            Equal-weight across {A.priced_count} simulated buy-and-hold positions</div>
        </div>
        <div style={{ display: 'flex', gap: 36, flexWrap: 'wrap' }}>
          {sub('$1k in each · now', fmtMoney(stakeTotals(data.positions).value),
            stakeTotals(data.positions).pnl >= 0 ? 'var(--buy)' : 'var(--pass)')}
          {sub('P&L', fmtMoneyDelta(stakeTotals(data.positions).pnl),
            stakeTotals(data.positions).pnl >= 0 ? 'var(--buy)' : 'var(--pass)')}
          {sub('Win rate', A.win_rate_pct == null ? '—' : A.win_rate_pct.toFixed(1) + '%')}
          {sub('Best · ' + (A.best?.ticker || ''), A.best ? fmtPct(A.best.return_pct) : '—', 'var(--buy)')}
          {sub('Worst · ' + (A.worst?.ticker || ''), A.worst ? fmtPct(A.worst.return_pct) : '—', 'var(--pass)')}
        </div>
      </div>
    );
  }

  function FullBookChart({ positions }) {
    const rows = positions.filter(p => p.return_pct != null).sort((a, b) => b.return_pct - a.return_pct);
    const config = {
      type: 'bar',
      data: {
        labels: rows.map(p => p.ticker),
        datasets: [{
          data: rows.map(p => p.return_pct),
          backgroundColor: rows.map(p => p.return_pct >= 0 ? BUY : PASS),
          borderRadius: 3, maxBarThickness: 14,
        }],
      },
      options: {
        ...baseOptions(false),
        plugins: {
          ...baseOptions(false).plugins,
          tooltip: {
            ...baseOptions(false).plugins.tooltip,
            callbacks: {
              title: items => {
                const p = rows[items[0].dataIndex];
                return `${p.ticker} — ${p.company_name}`;
              },
              label: item => {
                const p = rows[item.dataIndex];
                return [`Return ${fmtPct(p.return_pct)} · $1,000 → ${fmtMoney(stakeValue(p))}`,
                  `Entry ${p.entry_date} @ ${fmtPx(p.entry_price)}`,
                  `Latest ${fmtPx(p.latest_price)} · ${p.days_held} days`];
              },
            },
          },
        },
        scales: {
          x: { grid: { display: false }, border: { display: false },
               ticks: { font: { ...CHART_FONT, size: 8 }, color: '#9AA4B5', maxRotation: 90, minRotation: 90, autoSkip: false } },
          y: { grid: { display: true, color: '#EEF1F6' }, border: { display: false },
               ticks: { font: CHART_FONT, color: '#6B7A90', callback: v => v + '%' } },
        },
      },
    };
    return (
      <Card>
        <CardTitle>Every position, best to worst</CardTitle>
        <ChartCanvas config={config} height={280} />
      </Card>
    );
  }

  // Simulated P&L vs the real analysis spend that produced the book (ONC-771).
  function ReturnVsCost({ data, costs }) {
    const spend = costs?.totals?.tracked_total;
    if (spend == null || spend <= 0) return null;
    const S = stakeTotals(data.positions);
    const usd = v => '$' + v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    const up = S.pnl >= 0;
    const multiple = up && S.pnl > 0 ? S.pnl / spend : null;
    return (
      <div className="card" style={{
        borderLeft: `3px solid var(--${up ? 'buy' : 'pass'})`, borderRadius: '0 12px 12px 0',
        padding: '14px 20px', marginBottom: 14, fontSize: 13.5, lineHeight: 1.8, color: 'var(--ink-700)' }}>
        <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em',
          textTransform: 'uppercase', color: 'var(--ink-500)', display: 'block', marginBottom: 4 }}>
          Return vs cost</span>
        The simulated book is {up ? 'up' : 'down'} <Num>{fmtMoneyDelta(S.pnl)}</Num> ($1,000 per position)
        against <Num>{usd(spend)}</Num> of total analysis spend
        {multiple != null && <> — <Num>{multiple >= 10 ? Math.round(multiple) : multiple.toFixed(1)}×</Num> the cost of producing it</>}.
      </div>
    );
  }

  function ReturnsTab({ data, costsData, isElevated, onRefresh, refreshing }) {
    const asOf = data.prices_as_of
      ? new Date(data.prices_as_of).toISOString().slice(0, 16).replace('T', ' ') + 'Z' : '—';
    return (
      <div>
        <Hero data={data} />
        <ReturnVsCost data={data} costs={costsData} />
        {isElevated && (
          <div style={{ display: 'flex', marginBottom: 10 }}>
            <RefreshBtn onRefresh={onRefresh} refreshing={refreshing} />
          </div>
        )}
        <FullBookChart positions={data.positions} />
        <div style={{ display: 'grid', gridTemplateColumns: '5fr 7fr', gap: 14, alignItems: 'start' }}>
          <Cohorts cohorts={data.cohorts} />
          <div><Outliers outliers={data.outliers} /></div>
        </div>
        <PositionsTable positions={data.positions} />
        <Foot>{data.excluded_no_entry_price} early recommendations excluded (no entry price captured) · Dollar figures simulate $1,000 at each entry, listing-currency returns applied · Prices as of {asOf}</Foot>
      </div>
    );
  }

  function Num({ children }) {
    return <b style={{ fontFamily: MONO, fontWeight: 600, color: 'var(--ink-900)' }}>{children}</b>;
  }

  function CostsTab({ costs, returnsData }) {
    const T = costs.totals; const A = returnsData?.aggregates;
    const fmtUsd = v => v == null ? '—'
      : '$' + v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    return (
      <div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))', gap: 10, margin: '14px 0 12px' }}>
          <Kpi label="Total tracked spend" value={fmtUsd(T.tracked_total)} hint={`Since ${costs.coverage.tracking_began}`} />
          <Kpi label="This month" value={fmtUsd(T.this_month)} hint={`${T.tracked_runs} tracked runs total`} />
          <Kpi label="Avg cost / run" value={fmtUsd(T.avg_cost_per_run)}
            hint={T.avg_duration_s ? `≈ ${Math.round(T.avg_duration_s / 60)} min per run` : ''} />
          <Kpi label="Cost / BUY signal" value={fmtUsd(T.cost_per_buy)} tone="up" hint={`${T.tracked_buys} signals`} />
        </div>
        {A && (
          <div className="card" style={{
            borderLeft: '3px solid var(--buy)', borderRadius: '0 12px 12px 0',
            padding: '16px 20px', fontSize: 13.5, lineHeight: 1.8,
            color: 'var(--ink-700)', marginBottom: 14 }}>
            <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em',
              textTransform: 'uppercase', color: 'var(--ink-500)', display: 'block', marginBottom: 4 }}>
              What the spend bought</span>
            <Num>{fmtUsd(T.tracked_total)}</Num> of analysis compute produced <Num>{T.tracked_buys} BUY
            signals</Num> in the tracked period; the full BUY book of <Num>{A.position_count} positions</Num> is
            running at <Num>{fmtPct(A.avg_return_pct)}</Num> average simulated return
            ({A.win_rate_pct == null ? '—' : A.win_rate_pct.toFixed(1)}% win rate).
          </div>
        )}
        <Card>
          <CardTitle>Monthly analysis spend</CardTitle>
          <ColumnChart format={v => '$' + v} items={costs.months.map(m => ({
            label: m.month, sub: `${m.runs} runs · ${m.buys} BUYs`, value: m.cost, display: fmtUsd(m.cost), tone: 'neutral',
          }))} />
        </Card>
        <Foot>Cost capture began {costs.coverage.tracking_began} · {costs.coverage.untracked_runs} runs untracked (failed or pre-tracking)</Foot>
      </div>
    );
  }

  window.Returns = function Returns({ goto, session, isElevated }) {
    const { useState } = React;
    const [tab, setTab] = useState('returns');
    const [refreshing, setRefreshing] = useState(false);
    const sim = window.useApi(() => window.EQ_API.getSimulatedReturns(), []);
    const costs = window.useApi(() => window.EQ_API.getReturnsCosts(), []);

    const refresh = async () => {
      setRefreshing(true);
      try { await window.EQ_API.runReturnsSnapshot(true); sim.reload(); }
      catch (e) { console.error('Snapshot refresh failed:', e); }
      finally { setRefreshing(false); }
    };

    const tabBtn = (id, label) => (
      <button onClick={() => setTab(id)} style={{
        fontSize: 12.5, fontWeight: 600, letterSpacing: '0.02em',
        padding: '7px 22px', borderRadius: 6, cursor: 'pointer',
        background: tab === id ? 'var(--paper)' : 'transparent',
        color: tab === id ? 'var(--onni-primary)' : 'var(--ink-500)',
        border: tab === id ? '1px solid var(--ink-200)' : '1px solid transparent',
        boxShadow: tab === id ? 'var(--sh-1)' : 'none' }}>{label}</button>
    );

    // Frontend-only guard (server enforces require_elevated on the endpoints).
    // Mirrors the Strategies page: non-admins see a denial banner.
    const canSee = isElevated === true
      ? true
      : (window.EQ_IS_AUTHORIZED ? window.EQ_IS_AUTHORIZED(session) : false);
    if (!canSee) {
      return (
        <div>
          <window.TopBar title="Returns"/>
          <div style={{ padding: 32 }}>
            <window.ErrorBanner error={{ message: 'Returns is admin-only. Contact your administrator for access.' }}/>
          </div>
        </div>
      );
    }

    const loading = sim.loading || costs.loading;
    return (
      <div className="page-fade">
        <window.TopBar
          title="Returns"
          subtitle="Simulated buy-and-hold performance of BUY recommendations"
        />
        <div style={{ padding: '18px 32px 40px' }}>
          <div style={{ display: 'flex', gap: 2, background: 'var(--ink-150)', border: '1px solid var(--ink-200)',
            borderRadius: 8, padding: 3, width: 'fit-content', marginBottom: 4 }}>
            {tabBtn('returns', 'Returns')}{tabBtn('costs', 'Costs')}
          </div>
          {(sim.error || costs.error) && <window.ErrorBanner error={sim.error || costs.error} onRetry={() => { sim.reload(); costs.reload(); }} />}
          {loading && <div style={{ color: 'var(--ink-500)', fontSize: 12.5, padding: 20 }}>Loading…</div>}
          {!loading && tab === 'returns' && sim.data && (
            <ReturnsTab data={sim.data} costsData={costs.data} isElevated={isElevated} onRefresh={refresh} refreshing={refreshing} />
          )}
          {!loading && tab === 'costs' && costs.data && (
            <CostsTab costs={costs.data} returnsData={sim.data} />
          )}
        </div>
      </div>
    );
  };
})();
