/* Compare strategies — open to every approved user, not just admins.
   R-multiples and win rates only: no trader names, no account data, no $ P&L
   (which would reveal a real account's sizing). See src/strategy_stats.js. */

const CMP_PERIODS = [['1w', '1W'], ['1m', '1M'], ['3m', '3M'], ['6m', '6M'], ['1y', '1Y'], ['all', 'All']];
const CMP_POLICIES = [
  ['A', 'Fixed stop, first target'],
  ['B', 'Trailed to breakeven, scaled out'],
  ['D', 'Scaled out, fixed stop'],
];

const CMP_GLOSSARY = [
  ['R (risk unit)', 'The distance from entry to stop-loss, used as the yardstick instead of dollars. A trade that hits +2R made twice what it risked; -1R means it hit the stop and lost exactly what was risked. Comparable across symbols and account sizes.'],
  ['Win rate', 'The share of resolved trades that closed ahead (a positive R after fees).'],
  ['Avg R', "The average result per trade. Above 0 means the strategy's typical trade is profitable, before any position sizing."],
  ['Total R', "The sum of every trade's R in the window — the running track record, in risk units rather than dollars."],
  ['Max DD (drawdown)', 'The biggest peak-to-trough dip in the running R total during the window — a sense of how bumpy the ride can get, even if the strategy ends up profitable overall.'],
  ['Signals / Resolved', 'Signals = every valid setup posted in the window. Resolved = how many have played out far enough to be scored — the rest are still open or too recent to grade.'],
];

const CMP_POLICY_HELP = {
  A: 'Exits the whole position at the first target; the stop never moves. The simplest, most mechanical way to grade a setup.',
  B: "Moves the stop to breakeven once the first target hits, then scales out across the trader's further targets — rewards a setup that keeps running.",
  D: 'Scales out in equal slices across up to four targets; the stop never moves.',
};

function CmpGlossary() {
  const [open, setOpen] = React.useState(false);
  return (
    <div className="card">
      <div className="card-h" style={{ cursor: 'pointer' }} onClick={() => setOpen(o => !o)}>
        <span style={{ fontWeight: 600, fontSize: 13 }}>What do these numbers mean?</span>
        <span style={{ color: 'var(--text-4)', fontSize: 11 }}>{open ? '▲ hide' : '▼ show'}</span>
      </div>
      {open && (
        <div className="card-b" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(230px, 1fr))', gap: 12 }}>
          {CMP_GLOSSARY.map(([term, body]) => (
            <div key={term}>
              <div style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--text)', marginBottom: 3 }}>{term}</div>
              <div style={{ fontSize: 11.5, color: 'var(--text-3)', lineHeight: 1.5 }}>{body}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function cmpChip(active) {
  return {
    padding: '3px 9px', borderRadius: 6, fontSize: 11, cursor: 'pointer', fontFamily: 'var(--font-sans)',
    background: active ? 'var(--bg-card)' : 'transparent',
    border: '1px solid ' + (active ? 'var(--border)' : 'var(--border-soft)'),
    color: active ? 'var(--text)' : 'var(--text-3)', fontWeight: active ? 600 : 400,
  };
}

function CmpBars({ rows, metric }) {
  const vals = rows.map(r => r[metric]).filter(v => v != null);
  if (!vals.length) return <div style={{ color: 'var(--text-4)', fontSize: 12, padding: '18px 0' }}>No resolved trades in this window yet.</div>;
  const max = Math.max(...vals, 0), min = Math.min(...vals, 0);
  const span = (max - min) || 1;
  const zeroPct = ((0 - min) / span) * 100;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
      {rows.map(r => {
        const v = r[metric];
        const barPct = v == null ? 0 : (Math.abs(v) / span) * 100;
        const positive = v != null && v >= 0;
        return (
          <div key={r.strategy_id} style={{ display: 'grid', gridTemplateColumns: '110px 1fr 64px', gap: 10, alignItems: 'center' }}>
            <span style={{ fontSize: 11.5, color: 'var(--text-2)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.public_name}</span>
            <div style={{ position: 'relative', height: 14, background: 'var(--bg-elev)', borderRadius: 3 }}>
              <div style={{ position: 'absolute', left: `${zeroPct}%`, top: 0, bottom: 0, width: 1, background: 'var(--border)' }} />
              {v != null && (
                <div style={{
                  position: 'absolute', top: 1, bottom: 1, borderRadius: 3,
                  left: positive ? `${zeroPct}%` : `${zeroPct - barPct}%`, width: `${barPct}%`,
                  background: positive ? 'var(--bull)' : 'var(--bear)',
                }} />
              )}
            </div>
            <span className="mono" style={{ fontSize: 11.5, textAlign: 'right', color: v == null ? 'var(--text-4)' : (v >= 0 ? 'var(--bull)' : 'var(--bear)') }}>
              {v == null ? '—' : (v >= 0 ? '+' : '') + v.toFixed(2) + 'R'}
            </span>
          </div>
        );
      })}
    </div>
  );
}

const CMP_COL_HELP = {
  n_signals: 'Every valid setup this trader posted in the selected window.',
  n_resolved: 'How many of those have played out far enough to be scored — the rest are still open or too recent to grade.',
  win_rate: 'Share of resolved trades that closed ahead (a positive R after fees).',
  avg_r: 'Average result per trade, in R (risk units). Above 0 means the typical trade is profitable, before position sizing.',
  total_r: "Sum of every trade's R in the window — the running track record, comparable across strategies regardless of account size.",
  max_drawdown_r: 'The biggest peak-to-trough dip in the running R total during the window.',
};

function CmpTable({ rows, sort, setSort }) {
  const cols = [
    ['public_name', 'Strategy'], ['n_signals', 'Signals'], ['n_resolved', 'Resolved'],
    ['win_rate', 'Win rate'], ['avg_r', 'Avg R'], ['total_r', 'Total R'], ['max_drawdown_r', 'Max DD'],
  ];
  const th = { textAlign: 'left', fontSize: 9.5, color: 'var(--text-4)', letterSpacing: '0.08em', textTransform: 'uppercase', padding: '0 10px 8px', fontWeight: 500, cursor: 'pointer', userSelect: 'none' };
  const td = { padding: '8px 10px', borderTop: '1px solid var(--border-soft)', fontSize: 12 };
  const fmt = (col, v) => {
    if (v == null) return '—';
    if (col === 'win_rate') return (v * 100).toFixed(0) + '%';
    if (col === 'avg_r' || col === 'total_r' || col === 'max_drawdown_r') return (v >= 0 && col !== 'max_drawdown_r' ? '+' : '') + v.toFixed(2) + 'R';
    return v;
  };
  return (
    <table style={{ width: '100%', borderCollapse: 'collapse' }}>
      <thead><tr>
        {cols.map(([key, label]) => (
          <th key={key} style={th} title={CMP_COL_HELP[key]} onClick={() => setSort(s => ({
            key, dir: s.key === key ? (s.dir === 'desc' ? 'asc' : 'desc') : 'desc',
          }))}>
            {label}{CMP_COL_HELP[key] ? ' ⓘ' : ''}{sort.key === key ? (sort.dir === 'desc' ? ' ↓' : ' ↑') : ''}
          </th>
        ))}
      </tr></thead>
      <tbody>
        {rows.map(r => (
          <tr key={r.strategy_id}>
            {cols.map(([key]) => (
              <td key={key} style={{ ...td, fontFamily: key === 'public_name' ? 'var(--font-sans)' : 'var(--font-mono)',
                                      color: (key === 'avg_r' || key === 'total_r') && r[key] != null ? (r[key] >= 0 ? 'var(--bull)' : 'var(--bear)') : undefined,
                                      fontWeight: key === 'public_name' ? 600 : 400 }}>
                {fmt(key, r[key])}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

function W_StrategyCompare() {
  const [period, setPeriod] = React.useState('3m');
  const [policy, setPolicy] = React.useState('A');
  const [metric, setMetric] = React.useState('avg_r');
  const [hidden, setHidden] = React.useState(() => new Set());
  const [sort, setSort] = React.useState({ key: 'avg_r', dir: 'desc' });
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    let alive = true;
    fetch(`/api/strategies/compare?period=${period}&policy=${policy}`, { credentials: 'include' })
      .then(r => r.json())
      .then(j => { if (!alive) return; if (j.ok) { setData(j.data); setErr(null); } else setErr(j.error); })
      .catch(e => alive && setErr(String(e.message || e)));
    return () => { alive = false; };
  }, [period, policy]);

  if (err) return <div className="card"><div className="card-b" style={{ color: 'var(--bear)', fontSize: 12.5 }}>{err}</div></div>;
  if (!data) return <div style={{ color: 'var(--text-4)', fontSize: 12, padding: 20 }}>Loading…</div>;

  const visible = data.strategies.filter(s => !hidden.has(s.strategy_id));
  const sorted = [...visible].sort((a, b) => {
    const av = a[sort.key], bv = b[sort.key];
    const cmp = av == null && bv == null ? 0 : av == null ? 1 : bv == null ? -1
      : typeof av === 'string' ? av.localeCompare(bv) : av - bv;
    return sort.dir === 'desc' ? -cmp : cmp;
  });

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <CmpGlossary />

      <div className="card">
        <div className="card-b" style={{ display: 'flex', gap: 18, flexWrap: 'wrap', alignItems: 'center' }}>
          <div>
            <div style={{ ...acctLabelStyle, marginBottom: 6 }}>Period</div>
            <span style={{ display: 'flex', gap: 4 }}>
              {CMP_PERIODS.map(([id, label]) => (
                <button key={id} onClick={() => setPeriod(id)} style={cmpChip(period === id)}>{label}</button>
              ))}
            </span>
          </div>
          <div>
            <div style={{ ...acctLabelStyle, marginBottom: 6 }} title="Different simulated ways of managing the same trade after entry — compare them to see which style suits a strategy best.">Scored as ⓘ</div>
            <select value={policy} onChange={e => setPolicy(e.target.value)} title={CMP_POLICY_HELP[policy]} style={{ ...acctInp, width: 'auto', padding: '5px 8px' }}>
              {CMP_POLICIES.map(([id, label]) => <option key={id} value={id} title={CMP_POLICY_HELP[id]}>{label}</option>)}
            </select>
          </div>
          <div style={{ flex: 1, minWidth: 200 }}>
            <div style={{ ...acctLabelStyle, marginBottom: 6 }}>Strategies</div>
            <span style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
              {data.strategies.map(s => (
                <button key={s.strategy_id} onClick={() => setHidden(h => {
                  const n = new Set(h); n.has(s.strategy_id) ? n.delete(s.strategy_id) : n.add(s.strategy_id); return n;
                })} style={cmpChip(!hidden.has(s.strategy_id))}>{s.public_name}</button>
              ))}
            </span>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-h" style={{ justifyContent: 'space-between' }}>
          <span style={{ fontWeight: 600, fontSize: 13 }} title="Each bar is a strategy's average (or total) result across its resolved trades, measured in R — risk units, not dollars, so strategies stay comparable regardless of account size.">R by strategy ⓘ</span>
          <span style={{ display: 'flex', gap: 4 }}>
            <button onClick={() => setMetric('avg_r')} style={cmpChip(metric === 'avg_r')}>Avg R / trade</button>
            <button onClick={() => setMetric('total_r')} style={cmpChip(metric === 'total_r')}>Total R</button>
          </span>
        </div>
        <div className="card-b"><CmpBars rows={sorted} metric={metric} /></div>
      </div>

      <div className="card">
        <div className="card-h"><span style={{ fontWeight: 600, fontSize: 13 }}>All strategies</span></div>
        <div className="card-b" style={{ overflowX: 'auto' }}><CmpTable rows={sorted} sort={sort} setSort={setSort} /></div>
      </div>
    </div>
  );
}
