// Gauntlet Tab — visualizes saved Strategy Gauntlet artifacts (backtest/results/gauntlet-*.json).
// Read-only: the web NEVER runs a gauntlet (it would freeze the live server). It reads artifacts
// via GET /api/gauntlet/runs (list) and GET /api/gauntlet/run?file=... (one full run).
// Recharts/React are destructured INSIDE the component (function scope) to avoid redeclaring the
// top-level globals already declared in shared.jsx (no build step -> top-level redeclare = SyntaxError).

// --- pure helpers (gz-prefixed = unique global names, no conflict with shared.jsx) ---

// Cap a series to ~max points by striding; always keep the last point.
function gzDownsample(arr, max) {
  if (!Array.isArray(arr) || arr.length <= max) return arr || [];
  var stride = Math.ceil(arr.length / max);
  var out = [];
  for (var i = 0; i < arr.length; i += stride) out.push(arr[i]);
  if (out[out.length - 1] !== arr[arr.length - 1]) out.push(arr[arr.length - 1]);
  return out;
}

// Client-side alpha-adjusted score. MUST stay in sync with
// backtest/core/result-ranker.js scoreMetrics() mode 'alpha-adjusted'.
function gzAlphaScore(m) {
  if (!m) return 0;
  var tr = +m.totalReturnPct || 0, al = +m.alphaPct || 0, dd = +m.maxDrawdownPct || 0;
  var sh = +m.sharpe || 0, pf = +m.profitFactor || 0, tt = +m.totalTrades || 0;
  var pen = tt > 250 ? (tt - 250) * 0.02 : 0;
  return tr * 0.35 + al * 0.65 - dd * 1.5 + sh * 10 + Math.min(pf, 10) * 3 - pen;
}

var GZ_PALETTE = ["#f59e0b", "#22c55e", "#627eea", "#9945ff", "#ef4444", "#22d3ee", "#e879f9", "#84cc16", "#fb923c", "#94a3b8", "#f43f5e", "#14b8a6"];
function gzColor(i) { return GZ_PALETTE[i % GZ_PALETTE.length]; }
function gzNum(n, d) { if (n == null || isNaN(n)) return "—"; return (+n).toFixed(d == null ? 2 : d); }
// generatedAt is stored as UTC (Node toISOString). Render it in the viewer's LOCAL timezone.
function gzLocal(iso) {
  if (!iso) return "";
  var d = new Date(iso);
  if (isNaN(d.getTime())) return String(iso).slice(0, 16).replace("T", " ");
  var p = function (n) { return String(n).padStart(2, "0"); };
  return d.getFullYear() + "-" + p(d.getMonth() + 1) + "-" + p(d.getDate()) + " " + p(d.getHours()) + ":" + p(d.getMinutes());
}

// --- Plain-language glossary (Turkish) so non-experts can hover/read what each
// number means. Defined top-level with `var` (cross-script safe) and mirrored on
// window so gauntlet-analysis.jsx reuses the exact same wording. ---
var GZ_METRIC_INFO = {
  ret:     { t: "Toplam Getiri (%)", d: "Test boyunca paranın yüzde kaç değiştiği. +%100 = para 2'ye katlandı, -%50 = yarıya düştü." },
  alpha:   { t: "Alfa (%)", d: "Stratejinin 'al ve tut'a (buy & hold) kıyasla FAZLADAN getirisi. Pozitif = piyasayı yendi; negatif = sadece tutmak daha iyiydi. Çok negatifse, kıyas varlık o dönem çok yükselmiş demektir." },
  maxDD:   { t: "Maksimum Düşüş (%)", d: "Zirveden dibe yaşanan en büyük değer kaybı. %31 = bir noktada paranın %31'i erimiş. Düşük olması iyidir; ne kadar acı/dayanıklılık göstergesi." },
  sharpe:  { t: "Sharpe Oranı", d: "Alınan risk başına getiri (getiri / dalgalanma). >1 iyi, >2 çok iyi, <0 kötü. Aynı kazancı daha az iniş-çıkışla yapan yüksek puan alır." },
  pf:      { t: "Profit Factor (Kâr Faktörü)", d: "Kazanan işlemlerin toplamı / kaybeden işlemlerin toplamı. 1.65 = kazançlar kayıpların 1.65 katı. 1'in altı = net zararda." },
  trades:  { t: "İşlem Sayısı", d: "Test boyunca açılan/kapanan toplam al-sat adedi. Çok yüksek = aşırı işlem (komisyon yer + eğri-uydurma riski); çok düşük = az sinyal." },
  score:   { t: "Sıralama Skoru", d: "Gauntlet'in kazananı seçmek için kullandığı birleşik puan: getiri + alfa + Sharpe + PF ödüllendirilir, yüksek düşüş ve aşırı işlem sayısı cezalandırılır. '%' DEĞİLDİR, yalnızca sıralama içindir." },
  winRate: { t: "Kazanma Oranı (%)", d: "Kapanan işlemlerin yüzde kaçı kârla kapandı." },
};
var GZ_STATUS_INFO = {
  OK:            { t: "Sağlam", d: "Parametreler hem eğitim (train) hem de hiç görülmemiş (OOS) dönemde tutarlı çalıştı. Güvenilir.", c: "#22c55e" },
  OVERFIT_RISK:  { t: "Aşırı Uyum (Overfit) Riski", d: "Parametreler geçmiş veriye fazla uydurulmuş olabilir: eğitim döneminde harika ama hiç görülmemiş dönemde performans düştü. Gelecekte aynısını yapmayabilir.", c: "#f59e0b" },
  OOS_UNCERTAIN: { t: "OOS Belirsiz", d: "Görülmemiş dönemde yeterli işlem/veri olmadığı için güven düşük.", c: "#a5b4fc" },
  INELIGIBLE:    { t: "Elendi", d: "Minimum işlem/getiri eşiklerini geçemedi; finalist olamaz.", c: "#ef4444" },
};
var GZ_OVERFIT_INFO = "Overfit (aşırı uyum): bir strateji geçmiş veriyi adeta 'ezberlerse' testte mükemmel görünür ama gerçekte/gelecekte çöker. Gauntlet bunu yakalamak için veriyi İKİYE böler — train (parametrelerin arandığı dönem) ve OOS = out-of-sample (parametre seçildikten sonra hiç dokunulmamış son dönem). Bir parametre seti her iki dönemde de iyiyse OK; sadece train'de parlayıp OOS'ta sönüyorsa OVERFIT_RISK.";
var GZ_ENGINE_INFO = "Bu modeller XGBoost, sinir ağı veya transformer DEĞİLDİR — hiçbir makine öğrenmesi / yapay zeka kullanılmaz. Hepsi KURAL TABANLI klasik teknik analiz stratejisidir: fiyat ve indikatör (SMA, EMA, MACD, RSI, Bollinger, ATR...) koşullarına bakıp basit bir 'al / sat / bekle' kuralı uygular. Buradaki 'optimizasyon' da model eğitimi değildir; sadece parametre kombinasyonlarının ızgara taramasıdır (grid-search) + train/OOS doğrulaması.";
var GZ_STRATEGY_INFO = {
  "buy-hold": "Al ve Tut — başta alır, sonuna kadar tutar. Kıyas (benchmark) çizgisi.",
  "sma-cross": "SMA Kesişimi — hızlı basit hareketli ortalama yavaşı yukarı keserse al, aşağı keserse sat.",
  "ema-cross": "EMA Kesişimi — SMA Cross'un son fiyatlara daha duyarlı (üstel ortalama) versiyonu.",
  "macd-cross": "MACD Kesişimi — MACD histogramı sıfırı yukarı geçince al, aşağı geçince sat (momentum dönüşü).",
  "rsi-mean-reversion": "RSI Ortalamaya Dönüş — RSI aşırı satım bölgesine (ör. <30) düşünce al, aşırı alımda (>70) sat.",
  "bollinger-reversion": "Bollinger Dönüşü — fiyat alt banda değince al (ucuz), orta/üst banda dönünce sat.",
  "breakout": "Kanal Kırılımı — fiyat son N mumun zirvesini kırınca al (trend takibi), çıkış seviyesine düşünce sat; ATR bazlı stop.",
  "dma-trend": "KRAL Trend DMA — çift hareketli ortalama trend takibi; kademeli (parça parça) alım/satım.",
  "engine-core-profile": "Engine Core — canlı botun çok-sinyalli, rejim-ağırlıklı puanlama motoru: birden çok indikatörü ağırlıklandırıp buyScore/sellScore üretir, piyasa rejimine (trend/range) göre eşik ayarlar; risk ve stop yönetimi dahildir.",
};
var GZ_TH_KEY = { "ret%": "ret", "alpha%": "alpha", "maxDD%": "maxDD", "sharpe": "sharpe", "pf": "pf", "trades": "trades", "score": "score" };
function gzTipText(info) { return info ? info.t + " — " + info.d : null; }
if (typeof window !== "undefined") {
  window.GZ_METRIC_INFO = GZ_METRIC_INFO;
  window.GZ_STATUS_INFO = GZ_STATUS_INFO;
  window.GZ_OVERFIT_INFO = GZ_OVERFIT_INFO;
  window.GZ_ENGINE_INFO = GZ_ENGINE_INFO;
  window.GZ_STRATEGY_INFO = GZ_STRATEGY_INFO;
  window.gzTipText = gzTipText;
}

function GauntletTab({ isMobile }) {
  const { useState, useEffect, useMemo } = React;
  const {
    ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip, ReferenceLine,
    CartesianGrid, Legend,
  } = Recharts;

  const [runs, setRuns] = useState([]);
  const [file, setFile] = useState("");
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [rankBy, setRankBy] = useState("saved");        // 'saved' | 'alpha'
  const [showHelp, setShowHelp] = useState(false);      // glossary panel toggle

  // Load the recent runs list on mount.
  useEffect(function () {
    fetch("/api/gauntlet/runs")
      .then(function (r) { return r.json(); })
      .then(function (list) {
        list = Array.isArray(list) ? list : [];
        setRuns(list);
        if (list.length && !file) setFile(list[0].file);
      })
      .catch(function () { setRuns([]); });
  }, []);

  // Load the selected run.
  useEffect(function () {
    if (!file) { setData(null); return; }
    setLoading(true); setError(null);
    fetch("/api/gauntlet/run?file=" + encodeURIComponent(file))
      .then(function (r) { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then(function (j) { setData(j); })
      .catch(function (e) { setError(String(e.message || e)); setData(null); })
      .finally(function () { setLoading(false); });
  }, [file]);

  const bakeoff = (data && data.bakeoff) || [];
  const savedWinnerId = data && data.winner ? (data.winner.runId || data.winner.strategyId) : null;

  // Equity overlay: each finalist normalized to % growth from its own start, merged by date, downsampled.
  const overlay = useMemo(function () {
    var series = bakeoff
      .filter(function (r) { return r && Array.isArray(r.equityCurve) && r.equityCurve.length > 1; })
      .map(function (r) {
        var c = r.equityCurve;
        var base = c[0] && c[0].value > 0 ? c[0].value : 1;
        var map = {};
        c.forEach(function (p) { if (p && p.date) map[p.date] = (p.value / base - 1) * 100; });
        return { id: r.runId || r.strategyId, map: map };
      });
    var dset = {};
    bakeoff.forEach(function (r) { (r.equityCurve || []).forEach(function (p) { if (p && p.date) dset[p.date] = 1; }); });
    var allDates = gzDownsample(Object.keys(dset).sort(), 600);
    var rows = allDates.map(function (d) {
      var row = { date: d };
      series.forEach(function (s) { row[s.id] = s.map[d] != null ? +s.map[d].toFixed(2) : null; });
      return row;
    });
    // train/OOS boundary from the first optimization summary's split.
    var split = ((data && data.optimizationSummaries) || [])[0];
    var oosStart = split && split.split ? split.split.oosStartDate : null;
    var refDate = oosStart ? (allDates.find(function (d) { return d >= oosStart; }) || null) : null;
    return { rows: rows, ids: series.map(function (s) { return s.id; }), refDate: refDate };
  }, [data]);

  // Leaderboard rows respecting display-rank toggle (saved order is the JSON order).
  const board = useMemo(function () {
    var rows = bakeoff.slice();
    if (rankBy === "alpha") rows.sort(function (a, b) { return gzAlphaScore(b.metrics) - gzAlphaScore(a.metrics); });
    return rows;
  }, [data, rankBy]);

  function downloadCsv() {
    var head = ["rank", "runId", "strategyId", "totalReturnPct", "alphaPct", "maxDrawdownPct", "sharpe", "profitFactor", "totalTrades", "rankScore", "params"];
    var lines = [head.join(",")];
    board.forEach(function (r, i) {
      var m = r.metrics || {};
      lines.push([i + 1, (r.runId || r.strategyId), r.strategyId, m.totalReturnPct, m.alphaPct, m.maxDrawdownPct, m.sharpe, m.profitFactor, m.totalTrades, r.rankScore, '"' + JSON.stringify(r.params || {}).replace(/"/g, '""') + '"'].join(","));
    });
    var blob = new Blob([lines.join("\n") + "\n"], { type: "text/csv" });
    var url = URL.createObjectURL(blob);
    var a = document.createElement("a"); a.href = url; a.download = (file || "gauntlet").replace(/\.json$/, "") + "-leaderboard.csv";
    document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url);
  }

  // ---- styles ----
  var mono = "var(--m)", head = "var(--h)";
  var panel = { background: "#0d1117", border: "1px solid rgba(255,255,255,0.06)", borderRadius: 8, padding: 14, marginBottom: 14 };
  var h2 = { fontFamily: head, fontWeight: 700, fontSize: 13, color: "#f8fafc", marginBottom: 10, letterSpacing: "0.02em" };
  var th = { textAlign: "right", padding: "6px 8px", fontSize: 9, color: "#6b7280", fontFamily: head, fontWeight: 700, letterSpacing: "0.05em", borderBottom: "1px solid rgba(255,255,255,0.08)", whiteSpace: "nowrap" };
  var td = { textAlign: "right", padding: "6px 8px", fontSize: 11, fontFamily: mono, color: "#cbd5e1", whiteSpace: "nowrap" };

  function metricBadge(label, value, color, infoKey) {
    var info = infoKey ? GZ_METRIC_INFO[infoKey] : null;
    return (
      <div title={gzTipText(info) || undefined} style={{ background: "#0f172a", borderRadius: 6, padding: "8px 12px", minWidth: 92, cursor: info ? "help" : "default" }}>
        <div style={{ fontSize: 9, color: "#6b7280", fontFamily: head, fontWeight: 700, letterSpacing: "0.05em" }}>{label}{info && <span style={{ color: "#475569" }}> ⓘ</span>}</div>
        <div style={{ fontSize: 16, color: color || "#f8fafc", fontFamily: mono, fontWeight: 700 }}>{value}</div>
      </div>
    );
  }

  // Collapsible plain-language glossary: what every number means, what decision
  // mechanism the models use (NO ML), and what "overfit risk" is.
  function helpPanel() {
    var stratIds = data && Array.isArray(data.bakeoff)
      ? data.bakeoff.map(function (b) { return b.strategyId; }).filter(function (v, i, a) { return a.indexOf(v) === i; })
      : Object.keys(GZ_STRATEGY_INFO);
    var card = { background: "#0f172a", borderRadius: 8, padding: 12, marginBottom: 10 };
    var lbl = { fontSize: 11, color: "#f8fafc", fontFamily: head, fontWeight: 700, marginBottom: 6 };
    return (
      <div style={panel}>
        <div onClick={function () { setShowHelp(!showHelp); }} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", cursor: "pointer" }}>
          <div style={{ ...h2, marginBottom: 0 }}>📖 Bu sayfa ne anlatıyor? — metrikler, karar mekanizması, overfit</div>
          <span style={{ fontSize: 12, color: "#a5b4fc", fontFamily: mono }}>{showHelp ? "▲ gizle" : "▼ aç"}</span>
        </div>
        {showHelp && (
          <div style={{ marginTop: 12 }}>
            {/* Decision mechanism — the XGBoost/transformer question */}
            <div style={card}>
              <div style={lbl}>🧠 Bu modeller nasıl karar veriyor?</div>
              <div style={{ fontSize: 11, color: "#cbd5e1", fontFamily: mono, lineHeight: 1.6 }}>{GZ_ENGINE_INFO}</div>
              <div style={{ marginTop: 8, display: "flex", flexDirection: "column", gap: 4 }}>
                {stratIds.map(function (id) {
                  return GZ_STRATEGY_INFO[id]
                    ? <div key={id} style={{ fontSize: 10, fontFamily: mono, color: "#94a3b8" }}><b style={{ color: "#f59e0b" }}>{id}</b> — {GZ_STRATEGY_INFO[id]}</div>
                    : null;
                })}
              </div>
            </div>
            {/* Metric glossary */}
            <div style={card}>
              <div style={lbl}>📊 Metrikler ne anlama geliyor?</div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                {Object.keys(GZ_METRIC_INFO).map(function (k) {
                  var inf = GZ_METRIC_INFO[k];
                  return <div key={k} style={{ fontSize: 10, fontFamily: mono, color: "#94a3b8", lineHeight: 1.5 }}><b style={{ color: "#f8fafc" }}>{inf.t}</b> — {inf.d}</div>;
                })}
              </div>
            </div>
            {/* Overfit / robustness */}
            <div style={card}>
              <div style={lbl}>⚠️ "Overfit riski" / sağlamlık ne demek?</div>
              <div style={{ fontSize: 11, color: "#cbd5e1", fontFamily: mono, lineHeight: 1.6, marginBottom: 8 }}>{GZ_OVERFIT_INFO}</div>
              <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                {Object.keys(GZ_STATUS_INFO).map(function (k) {
                  var inf = GZ_STATUS_INFO[k];
                  return <div key={k} style={{ fontSize: 10, fontFamily: mono, color: "#94a3b8", lineHeight: 1.5 }}><b style={{ color: inf.c }}>{k}</b> ({inf.t}) — {inf.d}</div>;
                })}
              </div>
            </div>
          </div>
        )}
      </div>
    );
  }

  return (
    <div style={{ padding: isMobile ? 12 : 20 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 10, marginBottom: 6 }}>
        <div>
          <div style={{ fontFamily: head, fontWeight: 700, fontSize: 20, color: "#f8fafc" }}>Strategy Gauntlet</div>
          <div style={{ fontSize: 11, color: "#6b7280" }}>Kayitli backtest sonuclari · salt-okunur · CLI: <code style={{ color: "#a5b4fc" }}>npm run backtest:gauntlet</code></div>
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
          <select value={file} onChange={function (e) { setFile(e.target.value); }}
            style={{ background: "#0f172a", color: "#f8fafc", border: "1px solid rgba(255,255,255,0.12)", borderRadius: 6, padding: "7px 10px", fontFamily: mono, fontSize: 11, maxWidth: 360 }}>
            {!runs.length && <option value="">(kayitli kosu yok — once CLI ile koşturun)</option>}
            {runs.map(function (r) {
              return <option key={r.file} value={r.file}>
                {(gzLocal(r.generatedAt) || r.file)} · {(r.symbols || []).join(",")} · {r.finalistCount}🏁 · win:{r.winnerStrategyId}
              </option>;
            })}
          </select>
          {data && <a href={"/api/gauntlet/run?file=" + encodeURIComponent(file)} download
            style={{ fontSize: 10, color: "#a5b4fc", fontFamily: mono, textDecoration: "none", border: "1px solid rgba(165,180,252,0.3)", borderRadius: 5, padding: "6px 9px" }}>JSON ↓</a>}
          {data && <button onClick={downloadCsv} style={{ fontSize: 10, color: "#22c55e", fontFamily: mono, background: "none", border: "1px solid rgba(34,197,94,0.3)", borderRadius: 5, padding: "6px 9px", cursor: "pointer" }}>CSV ↓</button>}
        </div>
      </div>

      {helpPanel()}

      {loading && <div style={{ color: "#f59e0b", fontFamily: mono, fontSize: 13, padding: 20 }}>Yukleniyor…</div>}
      {error && <div style={{ color: "#ef4444", fontFamily: mono, fontSize: 12, padding: 14, background: "rgba(239,68,68,0.08)", borderRadius: 6 }}>Hata: {error}</div>}
      {!loading && !error && !data && !runs.length && (
        <div style={{ color: "#6b7280", fontFamily: mono, fontSize: 12, padding: 24, textAlign: "center", ...panel }}>
          Henuz kayitli gauntlet sonucu yok.<br />Terminalde: <code style={{ color: "#a5b4fc" }}>npm run backtest:gauntlet -- --symbols BTC,ETH,SOL --start 2021-01-01 --end 2024-12-31</code>
        </div>
      )}

      {data && (() => {
        var w = data.winner || {};
        var wm = w.metrics || {};
        var diff = data.differentiation || {};
        var ds = diff.summary || {};
        var split0 = (data.optimizationSummaries || [])[0];
        var sp = split0 && split0.split;
        return (
          <div>
            {/* SUMMARY / WINNER */}
            <div style={panel}>
              <div style={{ display: "flex", justifyContent: "space-between", flexWrap: "wrap", gap: 10, marginBottom: 10 }}>
                <div style={h2}>🏆 Kazanan (saved rank): <span style={{ color: gzColor(0) }}>{w.runId || w.strategyId}</span></div>
                <div style={{ fontSize: 10, color: "#6b7280", fontFamily: mono }}>
                  {(data.symbols || []).join(",")} · {sp ? sp.trainStartDate : "?"} → {sp ? sp.oosEndDate : "?"} · rank: {data.bakeoffRankMode || data.rankMode}
                </div>
              </div>
              <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 8 }}>
                {metricBadge("RETURN", gzNum(wm.totalReturnPct) + "%", wm.totalReturnPct >= 0 ? "#22c55e" : "#ef4444", "ret")}
                {metricBadge("ALPHA", gzNum(wm.alphaPct) + "%", wm.alphaPct >= 0 ? "#22c55e" : "#ef4444", "alpha")}
                {metricBadge("MAX DD", gzNum(wm.maxDrawdownPct) + "%", "#f59e0b", "maxDD")}
                {metricBadge("SHARPE", gzNum(wm.sharpe), "#a5b4fc", "sharpe")}
                {metricBadge("PF", gzNum(wm.profitFactor), "#cbd5e1", "pf")}
                {metricBadge("TRADES", wm.totalTrades, "#cbd5e1", "trades")}
                {metricBadge("SCORE", gzNum(w.rankScore), "#f59e0b", "score")}
              </div>
              <div style={{ fontSize: 10, color: "#64748b", fontFamily: mono }}>params: {JSON.stringify(w.params || {})}</div>
              <div title="Çeşitlilik: finalist stratejiler birbirine ne kadar benziyor. avg corr = getiri eğrilerinin ortalama korelasyonu (1'e yakın = neredeyse aynı), entry Jaccard = aynı günlerde alım yapma oranı. Düşük = daha çeşitli/bağımsız stratejiler (iyi)." style={{ marginTop: 8, fontSize: 11, color: "#94a3b8", fontFamily: mono, cursor: "help" }}>
                Çeşitlilik (benzerlik) ⓘ: ort. korelasyon <b style={{ color: "#f8fafc" }}>{gzNum(ds.avgEquityReturnCorrelation, 3)}</b> · giriş Jaccard <b style={{ color: "#f8fafc" }}>{gzNum(ds.avgEntryJaccard, 3)}</b> · {ds.pairCount} çift
              </div>
            </div>

            {/* LEADERBOARD */}
            <div style={panel}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
                <div style={h2}>Bakeoff Leaderboard</div>
                <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  <span style={{ fontSize: 9, color: "#6b7280", fontFamily: head }}>SIRALAMA</span>
                  {[["saved", "Saved (JSON)"], ["alpha", "Alpha-adjusted"]].map(function (o) {
                    return <button key={o[0]} onClick={function () { setRankBy(o[0]); }}
                      style={{ fontSize: 10, fontFamily: mono, padding: "4px 9px", borderRadius: 5, cursor: "pointer", border: "1px solid " + (rankBy === o[0] ? "#f59e0b" : "rgba(255,255,255,0.12)"), background: rankBy === o[0] ? "rgba(245,158,11,0.12)" : "none", color: rankBy === o[0] ? "#f59e0b" : "#94a3b8" }}>{o[1]}</button>;
                  })}
                </div>
              </div>
              {rankBy === "alpha" && <div style={{ fontSize: 10, color: "#a5b4fc", fontFamily: mono, marginBottom: 6 }}>↻ Goruntuleme sirasi (client-side alpha-adjusted) — kayitli kazanan degismez, 🏆 rozeti sabit.</div>}
              <div style={{ overflowX: "auto" }}>
                <table style={{ borderCollapse: "collapse", width: "100%", minWidth: 720 }}>
                  <thead><tr>
                    {["#", "run", "ret%", "alpha%", "maxDD%", "sharpe", "pf", "trades", "score"].map(function (c, i) {
                      var tip = c === "run" ? "Finalist kimliği — strateji + seçilen parametre kombinasyonu" : gzTipText(GZ_METRIC_INFO[GZ_TH_KEY[c]]);
                      return <th key={c} title={tip || undefined} style={{ ...th, textAlign: i < 2 ? "left" : "right", cursor: tip ? "help" : "default" }}>{c}{tip && i >= 2 ? <span style={{ color: "#475569" }}> ⓘ</span> : ""}</th>;
                    })}
                  </tr></thead>
                  <tbody>
                    {board.map(function (r, i) {
                      var m = r.metrics || {}; var id = r.runId || r.strategyId;
                      var isWin = id === savedWinnerId;
                      var score = rankBy === "alpha" ? gzAlphaScore(m) : r.rankScore;
                      return (
                        <tr key={id} style={{ background: isWin ? "rgba(245,158,11,0.08)" : "transparent", borderBottom: "1px solid rgba(255,255,255,0.04)" }}>
                          <td style={{ ...td, textAlign: "left", color: "#6b7280" }}>{i + 1}</td>
                          <td style={{ ...td, textAlign: "left", color: gzColor(i), fontWeight: 700 }}>{isWin && <span title="saved winner">🏆 </span>}{id}</td>
                          <td style={{ ...td, color: m.totalReturnPct >= 0 ? "#22c55e" : "#ef4444" }}>{gzNum(m.totalReturnPct)}</td>
                          <td style={{ ...td, color: m.alphaPct >= 0 ? "#22c55e" : "#ef4444" }}>{gzNum(m.alphaPct)}</td>
                          <td style={{ ...td, color: "#f59e0b" }}>{gzNum(m.maxDrawdownPct)}</td>
                          <td style={td}>{gzNum(m.sharpe)}</td>
                          <td style={td}>{gzNum(m.profitFactor)}</td>
                          <td style={td}>{m.totalTrades}</td>
                          <td style={{ ...td, color: "#f8fafc", fontWeight: 700 }}>{gzNum(score)}</td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>

            {/* EQUITY OVERLAY */}
            <div style={panel}>
              <div style={h2}>Equity Overlay <span style={{ fontWeight: 400, color: "#6b7280", fontSize: 10 }}>(% buyume, ~{overlay.rows.length} nokta/seri{overlay.refDate ? " · kirmizi cizgi = OOS baslangici" : ""})</span></div>
              <ResponsiveContainer width="100%" height={isMobile ? 240 : 340}>
                <LineChart data={overlay.rows} margin={{ top: 6, right: 10, left: 0, bottom: 0 }}>
                  <CartesianGrid stroke="rgba(255,255,255,0.05)" />
                  <XAxis dataKey="date" tick={{ fontSize: 9, fill: "#6b7280" }} minTickGap={40} />
                  <YAxis tick={{ fontSize: 9, fill: "#6b7280" }} tickFormatter={function (v) { return v + "%"; }} width={44} />
                  <Tooltip contentStyle={{ background: "#0f172a", border: "1px solid rgba(255,255,255,0.1)", fontSize: 11, fontFamily: mono }} formatter={function (v) { return gzNum(v) + "%"; }} />
                  <Legend wrapperStyle={{ fontSize: 9, fontFamily: mono }} />
                  {overlay.refDate && <ReferenceLine x={overlay.refDate} stroke="#ef4444" strokeDasharray="4 3" label={{ value: "OOS", fill: "#ef4444", fontSize: 9 }} />}
                  {overlay.ids.map(function (id, i) {
                    return <Line key={id} type="monotone" dataKey={id} stroke={gzColor(i)} dot={false} strokeWidth={id === savedWinnerId ? 2.4 : 1.2} connectNulls isAnimationActive={false} />;
                  })}
                </LineChart>
              </ResponsiveContainer>
            </div>

            {/* METHOD DEEP-DIVE + DECISION INSPECTOR (hero analysis) */}
            <GauntletAnalysis data={data} isMobile={isMobile} />
          </div>
        );
      })()}
    </div>
  );
}

window.GauntletTab = GauntletTab;
