// Top-level page composition — TopBar, ConfigScreen, Dashboard,
// running overlay, details modal, deploy toasts. Ported from
// design/design_handoff_nifty_bull/prototype/variant-a.jsx and wired
// to the real backend through window.API.

const POLL_INTERVAL_MS = 800;
const DEFAULT_AMOUNT = 500000;
const DEFAULT_MONTHS = 12;
// Default cap on per-trade size as a fraction of total capital. 5% is
// the value the dashboard used to hardcode — surface it as a control
// instead so the user can dial concentration up or down. The ₹10k
// floor below stays so a 1% setting on a tiny capital pool still
// produces a workable trade size.
const DEFAULT_MAX_PCT = 5;
const MIN_TRADE_FLOOR = 10000;

// Default backtest window: most recent 1 year through "today" (capped to
// the design's reference end-date so a fresh deploy with no market data
// for the past week still has a non-empty window).
function defaultDates() {
    const today = new Date();
    const end = today.toISOString().slice(0, 10);
    const startD = new Date(today.getTime() - 365 * 864e5);
    return { start: startD.toISOString().slice(0, 10), end };
}

function App() {
    const [strategies, setStrategies] = React.useState([]);
    const [stratLoadError, setStratLoadError] = React.useState(null);
    const [strategyId, setStrategyId] = React.useState(null);
    const [universes, setUniverses] = React.useState([]);
    const [universeId, setUniverseId] = React.useState('NIFTY_50');
    const [mode, setMode] = React.useState('lumpsum');
    const [amount, setAmount] = React.useState(DEFAULT_AMOUNT);
    const [months, setMonths] = React.useState(DEFAULT_MONTHS);
    const [maxPct, setMaxPct] = React.useState(DEFAULT_MAX_PCT);
    const dd = React.useMemo(defaultDates, []);
    const [startDate, setStartDate] = React.useState(dd.start);
    const [endDate, setEndDate] = React.useState(dd.end);
    const [detailsId, setDetailsId] = React.useState(null);

    const [screen, setScreen] = React.useState('config'); // config | running | dashboard
    const [jobId, setJobId] = React.useState(null);
    const [jobStatus, setJobStatus] = React.useState(null);
    const [result, setResult] = React.useState(null);
    const [runError, setRunError] = React.useState(null);

    const [toast, setToast] = React.useState(null);

    // Fetch strategies + universes on mount.
    React.useEffect(() => {
        API.listStrategies()
            .then((list) => {
                setStrategies(list);
                if (list.length && !strategyId) setStrategyId(list[0].id);
            })
            .catch((e) => setStratLoadError(e.message || 'Failed to load strategies'));
        API.listUniverses()
            .then(setUniverses)
            .catch((e) => console.warn('Failed to load universes:', e.message));
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    // Poll job status while running.
    React.useEffect(() => {
        if (screen !== 'running' || !jobId) return undefined;
        let cancelled = false;
        const tick = async () => {
            try {
                const data = await API.getBacktestStatus(jobId);
                if (cancelled) return;
                setJobStatus(data.status);
                if (data.status === 'COMPLETED') {
                    setResult(data.result);
                    setScreen('dashboard');
                } else if (data.status === 'FAILED') {
                    setRunError(data.error || 'Backtest failed');
                    setScreen('config');
                }
            } catch (e) {
                if (cancelled) return;
                setRunError(e.message || 'Polling failed');
                setScreen('config');
            }
        };
        const id = setInterval(tick, POLL_INTERVAL_MS);
        tick();
        return () => { cancelled = true; clearInterval(id); };
    }, [screen, jobId]);

    const selected = strategies.find((s) => s.id === strategyId);

    const onRun = async () => {
        if (!selected) return;
        setRunError(null);
        setResult(null);
        setJobStatus('QUEUED');
        setScreen('running');
        try {
            const body = {
                strategyName: strategyId,
                universe: universeId,
                startDate, endDate,
                initialCash: amount,
                minTradeAmount: 1000,
                // ₹10k floor preserves the previous safety net: a 1%
                // setting on a small capital pool still produces a
                // workable trade size rather than a sub-1k order.
                maxTradeAmount: Math.max(MIN_TRADE_FLOOR, Math.floor(amount * (maxPct / 100))),
                mode: mode === 'sip' ? 'SIP' : 'LUMPSUM',
                months: mode === 'sip' ? months : null,
            };
            const { jobId: newJobId } = await API.submitBacktest(body);
            setJobId(newJobId);
        } catch (e) {
            setRunError(e.message || 'Failed to submit backtest');
            setScreen('config');
        }
    };

    // Deploy-to-broker is aspirational and not yet implemented.
    // The Dashboard header used to show a "Deploy live" button here;
    // when that capability returns it will use a fresh wire to a real
    // adapter rather than the previous half-implemented path.

    const reset = () => {
        setScreen('config');
        setJobId(null);
        setJobStatus(null);
        setResult(null);
    };

    if (stratLoadError) {
        return (
            <div className="app-shell">
                <TopBar screen="config" />
                <div style={{ maxWidth: 720, margin: '80px auto', padding: 24 }}>
                    <div className="card" style={{ padding: 24 }}>
                        <h2 style={{ marginTop: 0 }}>Couldn't load strategies</h2>
                        <p style={{ color: 'var(--text-2)' }}>{stratLoadError}</p>
                        <button className="btn" onClick={() => window.location.reload()}>Reload</button>
                    </div>
                </div>
            </div>
        );
    }

    if (strategies.length === 0) {
        return (
            <div className="app-shell">
                <TopBar screen="config" />
                <div className="empty">Loading strategies…</div>
            </div>
        );
    }

    return (
        <div className="app-shell">
            <TopBar screen={screen === 'dashboard' || screen === 'running' ? 'dashboard' : 'config'} />

            {screen === 'config' && (
                <ConfigScreen
                    strategies={strategies}
                    strategyId={strategyId} setStrategyId={setStrategyId}
                    universes={universes}
                    universeId={universeId} setUniverseId={setUniverseId}
                    mode={mode} setMode={setMode}
                    amount={amount} setAmount={setAmount}
                    months={months} setMonths={setMonths}
                    maxPct={maxPct} setMaxPct={setMaxPct}
                    startDate={startDate} setStartDate={setStartDate}
                    endDate={endDate} setEndDate={setEndDate}
                    onSeeDetails={setDetailsId}
                    onRun={onRun}
                    runError={runError}
                />
            )}

            {(screen === 'running' || screen === 'dashboard') && result && (
                <Dashboard
                    strategy={selected}
                    mode={mode} amount={amount} months={months}
                    startDate={startDate} endDate={endDate}
                    summary={result}
                    onReset={reset}
                />
            )}

            {screen === 'running' && (
                <UI.BacktestRunning strategy={selected} jobStatus={jobStatus} />
            )}

            {detailsId && (
                <UI.StrategyModal strategy={strategies.find((s) => s.id === detailsId)} onClose={() => setDetailsId(null)} />
            )}

            {toast && (
                <div className={`toast ${toast.kind}`}>{toast.text}</div>
            )}
        </div>
    );
}

function TopBar({ screen }) {
    return (
        <div style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            padding: '18px 40px',
            borderBottom: '1px solid var(--border)',
            background: 'var(--surface)',
        }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <div style={{
                    width: 38, height: 38, borderRadius: 10,
                    background: 'var(--accent)',
                    color: 'white',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    boxShadow: 'var(--shadow-selected)',
                }}>
                    <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M5.5 8.5 L7.5 5 L9.8 6.2" />
                        <path d="M18.5 8.5 L16.5 5 L14.2 6.2" />
                        <path d="M6 10.5 C6 14.5, 9 18.5, 12 18.5 C15 18.5, 18 14.5, 18 10.5 C18 8.5, 16 7, 12 7 C8 7, 6 8.5, 6 10.5 Z" />
                        <circle cx="9.5" cy="11.5" r="0.95" fill="currentColor" stroke="none" />
                        <circle cx="14.5" cy="11.5" r="0.95" fill="currentColor" stroke="none" />
                        <path d="M10.3 14.6 Q12 15.9 13.7 14.6" />
                    </svg>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', lineHeight: 1 }}>
                    <div style={{
                        fontFamily: "'Playfair Display', Georgia, serif",
                        fontSize: 20, fontWeight: 800, letterSpacing: '-0.018em',
                    }}>Nifty Bull</div>
                    <div style={{
                        fontFamily: "'JetBrains Mono', monospace",
                        fontSize: 9.5, color: 'var(--text-3)', letterSpacing: '0.2em',
                        textTransform: 'uppercase', marginTop: 4,
                    }}>Algo Trading</div>
                </div>
                <span className="pill" style={{ marginLeft: 8, fontSize: 10.5 }}>
                    {screen === 'config' ? 'New backtest' : 'Results'}
                </span>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 20 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 7, fontSize: 12.5, color: 'var(--text-2)' }}>
                    <span style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--accent)', boxShadow: '0 0 0 3px var(--accent-ring)' }} />
                    NSE · Historical
                </div>
                <div style={{
                    width: 32, height: 32, borderRadius: '50%',
                    background: 'var(--accent-soft)', color: 'var(--accent-text)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontSize: 12, fontWeight: 600,
                }}>AP</div>
            </div>
        </div>
    );
}

function ConfigScreen({ strategies, strategyId, setStrategyId, universes, universeId, setUniverseId,
    mode, setMode, amount, setAmount, months, setMonths, maxPct, setMaxPct,
    startDate, setStartDate, endDate, setEndDate,
    onSeeDetails, onRun, runError }) {
    const selected = strategies.find((s) => s.id === strategyId) || strategies[0];
    const selectedUniverse = (universes || []).find((u) => u.id === universeId);

    const capitalPresets = [
        { v: 100000, label: '1L' },
        { v: 250000, label: '2.5L' },
        { v: 500000, label: '5L' },
        { v: 1000000, label: '10L' },
        { v: 2500000, label: '25L' },
    ];

    const today = new Date().toISOString().slice(0, 10);
    const dateRanges = [
        { label: '6 months', s: shiftDays(today, -180), e: today },
        { label: '1 year', s: shiftDays(today, -365), e: today },
        { label: '2 years', s: shiftDays(today, -730), e: today },
        { label: '5 years', s: shiftDays(today, -1825), e: today },
    ];

    const isRangeMatch = (s, e) => startDate === s && endDate === e;

    return (
        <div className="fade-in" style={{ maxWidth: 1120, margin: '0 auto', padding: '48px 40px 72px' }}>
            <div style={{ marginBottom: 36 }}>
                <div style={{ fontSize: 12, color: 'var(--text-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 10 }}>
                    New backtest
                </div>
                <h1 style={{ margin: 0, fontSize: 40, fontWeight: 600, letterSpacing: '-0.025em', lineHeight: 1.05 }}>
                    Let's configure your bot.
                </h1>
                <p style={{ margin: '12px 0 0', color: 'var(--text-2)', fontSize: 15.5, maxWidth: 620, lineHeight: 1.55 }}>
                    Pick a strategy, set how you'll fund it, and choose a window. We'll run the simulation on historical NSE data and show you exactly how it would have performed.
                </p>
                {runError && (
                    <div className="toast error" style={{ position: 'static', marginTop: 16, maxWidth: 560 }}>
                        {runError}
                    </div>
                )}
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 340px', gap: 28, alignItems: 'start' }}>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
                    <div className="card" style={{ padding: 28 }}>
                        <SectionHead step="01" title="Strategy" subtitle={`Choose one of ${strategies.length} pre-built algorithmic strategies`} />
                        <UI.StrategyPicker strategies={strategies} value={strategyId} onChange={setStrategyId} />
                        <div style={{
                            marginTop: 16, padding: 16,
                            background: 'var(--bg-2)', borderRadius: 10,
                            display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 14,
                            border: '1px solid var(--border)',
                        }}>
                            <p style={{ margin: 0, fontSize: 13.5, color: 'var(--text-2)', lineHeight: 1.55 }}>
                                {selected.short}
                            </p>
                            <button className="btn sm" onClick={() => onSeeDetails(selected.id)} style={{ flex: 'none' }}>
                                <UI.Icon.Info /> See details
                            </button>
                        </div>
                    </div>

                    <div className="card" style={{ padding: 28 }}>
                        <SectionHead step="02" title="Universe"
                            subtitle="Which slice of the NSE the strategy can pick stocks from" />
                        <div className="seg" style={{ marginBottom: 14 }}>
                            {(universes || []).map((u) => (
                                <button key={u.id}
                                    className={u.id === universeId ? 'active' : ''}
                                    onClick={() => setUniverseId(u.id)}>
                                    {u.name}
                                </button>
                            ))}
                            {(!universes || universes.length === 0) && (
                                <div style={{ padding: '8px 12px', color: 'var(--text-3)', fontSize: 12 }}>
                                    Loading universes…
                                </div>
                            )}
                        </div>
                        {selectedUniverse && (
                            <div style={{
                                padding: 14, background: 'var(--bg-2)', borderRadius: 10,
                                fontSize: 13, color: 'var(--text-2)', lineHeight: 1.55,
                                border: '1px solid var(--border)',
                            }}>
                                {selectedUniverse.description}
                                <span style={{ display: 'block', marginTop: 6, fontSize: 12, color: 'var(--text-3)' }}>
                                    {selectedUniverse.constituentCount > 0
                                        ? `${selectedUniverse.constituentCount} constituents currently loaded.`
                                        : 'Universe not loaded yet — click Run to seed it from NSE.'}
                                </span>
                            </div>
                        )}
                    </div>

                    <div className="card" style={{ padding: 28 }}>
                        <SectionHead step="03" title="Capital allocation" subtitle="All at once, or drip-feed it monthly" />
                        <div className="seg" style={{ marginBottom: 22 }}>
                            <button className={mode === 'lumpsum' ? 'active' : ''} onClick={() => setMode('lumpsum')}>Lumpsum</button>
                            <button className={mode === 'sip' ? 'active' : ''} onClick={() => setMode('sip')}>Monthly SIP</button>
                        </div>
                        <div style={{ display: 'grid', gridTemplateColumns: mode === 'sip' ? '1fr 1fr' : '1fr', gap: 20 }}>
                            <div>
                                <label className="label">Total capital (₹)</label>
                                <div style={{ position: 'relative' }}>
                                    <span style={{ position: 'absolute', left: 14, top: '50%', transform: 'translateY(-50%)', color: 'var(--text-3)', fontSize: 16 }}>₹</span>
                                    <input className="input mono" style={{ paddingLeft: 30, fontSize: 16, padding: '14px 14px 14px 30px', fontWeight: 600 }}
                                        value={amount.toLocaleString('en-IN')}
                                        onChange={(e) => {
                                            const v = parseInt(e.target.value.replace(/[^\d]/g, ''), 10) || 0;
                                            setAmount(v);
                                        }} />
                                </div>
                                <div style={{ display: 'flex', gap: 6, marginTop: 12, flexWrap: 'wrap' }}>
                                    {capitalPresets.map((p) => (
                                        <button key={p.v} type="button"
                                            className={`btn xs chip ${amount === p.v ? 'selected' : ''}`}
                                            onClick={() => setAmount(p.v)}>
                                            ₹{p.label}
                                        </button>
                                    ))}
                                </div>
                            </div>
                            {mode === 'sip' && (
                                <div>
                                    <label className="label">Split across (months)</label>
                                    <input className="input mono" type="number" min="2" max="60" value={months}
                                        style={{ fontSize: 16, padding: '14px 14px', fontWeight: 600 }}
                                        onChange={(e) => setMonths(Math.max(2, Math.min(60, parseInt(e.target.value, 10) || 12)))} />
                                    <div style={{ marginTop: 12, padding: '10px 12px', background: 'var(--accent-softer)', borderRadius: 8, fontSize: 12.5, color: 'var(--accent-text)', border: '1px solid var(--accent-soft)' }}>
                                        <span className="mono" style={{ fontWeight: 600 }}>
                                            {UI.fmtINR(amount / months, { compact: true })}
                                        </span> deployed on the 1st of each month
                                    </div>
                                </div>
                            )}
                        </div>

                        {/* Risk-per-trade — caps how much capital any single buy can
                            deploy. Enforced inside each Strategy impl
                            (AAMR/RSISniper/Pullback all clamp to maxTradeAmount).
                            Lower → many small bets, more diversified, takes longer
                            to deploy; higher → fewer concentrated bets, larger
                            drawdowns. */}
                        <div style={{ marginTop: 24, paddingTop: 20, borderTop: '1px solid var(--border)' }}>
                            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10 }}>
                                <label className="label" style={{ marginBottom: 0, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                                    Max per trade
                                    <UI.Hint width={300}>
                                        <strong>Max per Trade</strong> — hard cap on how much capital
                                        any single BUY can deploy, expressed as a percent of total
                                        capital. Each strategy clamps its position-sizing logic to this
                                        ceiling, so a strong signal can't put more than this fraction
                                        on one stock. Lower → more trades, more diversification, slower
                                        to deploy. Higher → fewer concentrated bets, larger drawdowns
                                        if any one position turns. The resolved ₹ figure has a{' '}
                                        <code>₹10,000</code> floor so a 1% setting on small capital
                                        still produces a workable trade size.
                                    </UI.Hint>
                                </label>
                                <div className="mono" style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>
                                    {maxPct}% ·{' '}
                                    <span style={{ color: 'var(--text-2)' }}>
                                        {UI.fmtINR(Math.max(MIN_TRADE_FLOOR, Math.floor(amount * (maxPct / 100))), { compact: true })}
                                    </span>
                                </div>
                            </div>
                            <input type="range" min="1" max="25" step="1"
                                value={maxPct}
                                onChange={(e) => setMaxPct(parseInt(e.target.value, 10) || 1)}
                                style={{ width: '100%', accentColor: 'var(--accent)' }} />
                            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10.5, color: 'var(--text-3)', fontFamily: 'var(--font-mono)', marginTop: 4 }}>
                                <span>1% · diversified</span>
                                <span>5% · default</span>
                                <span>25% · concentrated</span>
                            </div>
                        </div>
                    </div>

                    <div className="card" style={{ padding: 28 }}>
                        <SectionHead step="04" title="Backtest window" subtitle="Which historical period to simulate" />
                        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginBottom: 14 }}>
                            <div>
                                <label className="label">Start date</label>
                                <input className="input" type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} />
                            </div>
                            <div>
                                <label className="label">End date</label>
                                <input className="input" type="date" value={endDate} onChange={(e) => setEndDate(e.target.value)} />
                            </div>
                        </div>
                        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                            {dateRanges.map((p) => (
                                <button key={p.label} type="button"
                                    className={`btn xs chip ${isRangeMatch(p.s, p.e) ? 'selected' : ''}`}
                                    onClick={() => { setStartDate(p.s); setEndDate(p.e); }}>
                                    {p.label}
                                </button>
                            ))}
                        </div>
                    </div>
                </div>

                <div style={{ position: 'sticky', top: 24 }}>
                    <div className="card" style={{ padding: 22, boxShadow: 'var(--shadow-md)' }}>
                        <div style={{ fontSize: 11.5, color: 'var(--text-3)', letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: 16, fontWeight: 500 }}>
                            Summary
                        </div>
                        <SummaryRow label="Strategy" value={selected.name} />
                        <SummaryRow label="Category" value={selected.category} />
                        <SummaryRow label="Capital" value={UI.fmtINR(amount, { compact: true })} />
                        <SummaryRow label="Mode" value={mode === 'lumpsum' ? 'Lumpsum' : `SIP × ${months}mo`} />
                        <SummaryRow label="Max / trade"
                            value={`${maxPct}% · ${UI.fmtINR(Math.max(MIN_TRADE_FLOOR, Math.floor(amount * (maxPct / 100))), { compact: true })}`} />
                        <SummaryRow label="From" value={UI.fmtDate(new Date(startDate))} />
                        <SummaryRow label="To" value={UI.fmtDate(new Date(endDate))} />
                        <SummaryRow label="Universe"
                            value={selectedUniverse ? selectedUniverse.name : universeId.replace('_', ' ')}
                            last />

                        <button className="btn accent" style={{ width: '100%', marginTop: 20, padding: '14px', fontSize: 14.5, justifyContent: 'center' }} onClick={onRun}>
                            <UI.Icon.Play /> Run backtest
                        </button>
                        <div style={{ fontSize: 11.5, color: 'var(--text-3)', textAlign: 'center', marginTop: 12 }}>
                            Simulation runs on the server — usually 5–30s depending on window.
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

function shiftDays(isoDate, delta) {
    const d = new Date(isoDate);
    d.setDate(d.getDate() + delta);
    return d.toISOString().slice(0, 10);
}

function SectionHead({ step, title, subtitle }) {
    return (
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 20 }}>
            <div className="mono" style={{
                width: 32, height: 32, borderRadius: 8,
                background: 'var(--surface-2)', border: '1px solid var(--border)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontSize: 11.5, fontWeight: 600, color: 'var(--text-2)',
            }}>{step}</div>
            <div>
                <div style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-0.008em' }}>{title}</div>
                <div style={{ fontSize: 12.5, color: 'var(--text-3)', marginTop: 2 }}>{subtitle}</div>
            </div>
        </div>
    );
}

function SummaryRow({ label, value, last }) {
    return (
        <div style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10,
            padding: '10px 0', borderBottom: last ? 'none' : '1px solid var(--border)',
        }}>
            <span style={{ fontSize: 12, color: 'var(--text-3)' }}>{label}</span>
            <span className="mono" style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)', textAlign: 'right' }}>{value}</span>
        </div>
    );
}

function Dashboard({ strategy, mode, amount, months, startDate, endDate, summary, onReset }) {
    const kpis = summary.kpis || {};
    const curve = summary.curve || [];
    const trades = summary.trades || [];

    return (
        <div className="fade-in" style={{ maxWidth: 1400, margin: '0 auto', padding: '32px 40px 72px' }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, marginBottom: 28 }}>
                <div>
                    <button className="btn ghost sm" onClick={onReset} style={{ marginBottom: 14, padding: '6px 10px', marginLeft: -10 }}>
                        <UI.Icon.Back /> New backtest
                    </button>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                        <span className="pill accent">{strategy.category}</span>
                        <span className="pill">{mode === 'lumpsum' ? 'Lumpsum' : `SIP × ${months}mo`}</span>
                        <span className="pill">{UI.fmtINR(amount, { compact: true })}</span>
                    </div>
                    <h1 style={{ margin: 0, fontSize: 34, fontWeight: 600, letterSpacing: '-0.022em', lineHeight: 1.1 }}>
                        {strategy.name} · Backtest results
                    </h1>
                    <div style={{ fontSize: 13.5, color: 'var(--text-3)', marginTop: 8 }}>
                        {UI.fmtDate(new Date(startDate))} — {UI.fmtDate(new Date(endDate))} · {summary.benchmarkLabel || 'NIFTY 50'} universe
                    </div>
                </div>
                {/* "Deploy live" button used to live here. Removed when
                    the deploy-to-broker path was retired as aspirational. */}
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 14, marginBottom: 22 }}>
                <UI.KPITile label="Total return"
                    value={UI.fmtPct(kpis.totalReturnPct || 0)}
                    delta={`${(kpis.totalReturnPct || 0) >= 0 ? 'Profit' : 'Loss'}`}
                    good={(kpis.totalReturnPct || 0) >= 0 ? 'up' : 'down'}
                    highlight={(kpis.totalReturnPct || 0) > 0}
                    hint={<>
                        <strong>Total Return</strong> — final portfolio value vs the
                        capital you committed, as a percent. Includes both <em>realised</em>
                        gains (closed sells) and <em>unrealised</em> gains (open holdings
                        marked-to-market on the last day). Formula: <code>(final / initial − 1) × 100</code>.
                    </>} />
                <UI.KPITile label="CAGR"
                    value={UI.fmtPct(kpis.cagrPct || 0)}
                    good={(kpis.cagrPct || 0) >= 0 ? 'up' : 'down'}
                    deltaLabel="annualised"
                    delta={(kpis.cagrPct || 0) > 14 ? 'Strong' : 'Moderate'}
                    hint={<>
                        <strong>Compound Annual Growth Rate</strong> — the constant annual
                        return that would have produced the same final value over the same
                        calendar window. Formula: <code>(final / initial)^(1/years) − 1</code>.
                        Backtest windows shorter than a year extrapolate the partial-period
                        return out to a full year, so a strong 3-month run can show a
                        triple-digit CAGR. SIP runs over-state CAGR because money wasn't
                        invested for the full window.
                    </>} />
                <UI.KPITile label="Max drawdown"
                    value={UI.fmtPct(kpis.maxDrawdownPct || 0)}
                    good="down"
                    delta="Peak to trough"
                    hint={<>
                        <strong>Maximum Drawdown</strong> — largest peak-to-trough drop of
                        the total portfolio value during the run, as a negative percent.
                        Formula: walk the curve, track the running peak, return the lowest
                        observed <code>(value − peak) / peak</code>. A risk-of-ruin proxy:
                        deeper drawdowns mean longer recovery time and more emotional pain
                        in real money.
                    </>} />
                <UI.KPITile label="Sharpe ratio"
                    value={(kpis.sharpeRatio || 0).toFixed(2)}
                    good={(kpis.sharpeRatio || 0) >= 1 ? 'up' : 'down'}
                    delta="Risk-adjusted"
                    hint={<>
                        <strong>Sharpe Ratio</strong> — risk-adjusted return: average daily
                        portfolio return divided by the standard deviation of those returns,
                        annualised by <code>√252</code>. Risk-free rate is treated as zero.
                        Rules of thumb: <strong>&gt;1</strong> decent,
                        <strong> &gt;2</strong> strong, <strong>&gt;3</strong> exceptional.
                        Caveat: SIP mode tends to over-state Sharpe because monthly cash
                        injections show up as positive return days.
                    </>} />
                <UI.KPITile label="Win rate"
                    value={`${(kpis.winRatePct || 0).toFixed(0)}%`}
                    delta={`${kpis.winningTrades || 0}/${kpis.closedTrades || 0} trades`}
                    good={(kpis.winRatePct || 0) >= 50 ? 'up' : 'down'}
                    hint={<>
                        <strong>Win Rate</strong> — closing trades (sells) with positive
                        realised P&amp;L divided by total closing trades. Buys don't count —
                        they're only opening trades. Ignores currently-held positions, even
                        if they're up or down on paper. A 50%+ win rate is good; even
                        sub-50% can be profitable if winners are larger than losers.
                    </>} />
            </div>

            <div style={{ marginBottom: 22 }}>
                <PortfolioChart
                    curve={curve}
                    benchmarkCurve={summary.benchmarkCurve}
                    benchmarkLabel={summary.benchmarkLabel} />
            </div>

            <TradesTable trades={trades} windowStart={startDate} windowEnd={endDate} />

            <HoldingsCard summary={summary} />
        </div>
    );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
