{% extends "base.html" %}
{% from "_macros.html" import exec_badge %}
{% block title %}Replay{% endblock %}
{% block body %}
{# ===== REPLAY: the RECORDED Bybit paper book (the cockpit's only venue), scrubbed day-by-day — same
   header/section/badge skin as Overview + Paper. Forward-only and fixed (unlike the configurable Backtest);
   the scrubber + as-of book are the unique detail this page provides. PAPER-badged (it's the paper
   record). ===== #}
{# Track switch — Naive (the recorded paper book, scrubbable positions) vs Levered shadow (the observe-only
   levered forward_nav curve, return-defined, no positions). Relative URLs only. #}
<div style="display:flex; gap:8px; margin-bottom:10px">
  <a href="/paper/replay?track=naive"
     style="text-decoration:none; padding:6px 14px; border-radius:6px; border:1px solid #30363d;
            {% if track != 'levered' %}background:#1f6feb22; color:#58a6ff; border-color:#1f6feb{% else %}background:#161b22; color:#8b949e{% endif %}">Naive
     <span class="muted" style="font-size:11px">· deploy</span></a>
  <a href="/paper/replay?track=levered"
     style="text-decoration:none; padding:6px 14px; border-radius:6px; border:1px solid #30363d;
            {% if track == 'levered' %}background:#1f6feb22; color:#58a6ff; border-color:#1f6feb{% else %}background:#161b22; color:#8b949e{% endif %}">Levered
     <span class="muted" style="font-size:11px">· shadow</span></a>
</div>

<div class="section">
{# ── TRADER HEADER: h1 + a plain-language orientation verdict, consistent with the strategy page. Neutral —
   it frames what the record IS. Avoids the retired copy the tests forbid. #}
  <h1 style="margin:0 0 2px">Replay {{ exec_badge('paper') }}</h1>
  <div class="muted" style="font-size:12.5px; margin-bottom:12px">the recorded paper book, scrubbed day-by-day</div>
  <div class="verdict" style="margin-bottom:16px">
    {% if track == 'levered' %}
    <b>The levered shadow track.</b> An observe-only levered version of the deploy book — return-defined, so
    there are no positions to scrub. For the measured backtest curve use the
    <a href="/paper/sim?book=bybit_4edge_levered">levered Backtest</a>.
    {% else %}
    <b>The real forward record — what actually happened.</b> The live-paper NAV, positions and trades for the
    Bybit deploy book, exactly as they were booked. Drag the slider to any day to see the book as it stood.
    Forward-only and fixed; for a what-if on capital or dates, use the <a href="/paper/sim">Backtest</a>.
    {% endif %}
  </div>

{% if track == 'levered' %}
  {% if levered_days and levered_days >= 2 %}
  <div>{{ curve|safe }}</div>
  <p class="muted" style="font-size:12px">Levered shadow ({{ levered_days }} recorded day{{ '' if levered_days == 1 else 's' }}) — return-defined, so it has NO scrubbable positions. For the measured backtest curve see the
    <a href="/paper/sim?book=bybit_4edge_levered">levered Backtest</a>.</p>
  {% else %}
  <p class="muted">The levered shadow track just started (T0 frozen) — its recorded curve appears here as it accrues days. Meanwhile see the
    <a href="/paper/sim?book=bybit_4edge_levered">levered Backtest</a>.</p>
  {% endif %}
{% else %}
{% if not hist %}
  <p class="muted">no replay history yet — run <code>fxhnt bybit-paper-backfill</code> to build the equity series.</p>
{% else %}
<div>{{ curve|safe }}</div>

<p class="muted" style="font-size:12px">xsfunding (carry) is return-defined (live-only) — it has no scrubbable positions, so it's excluded from the position replay.</p>

<div style="display:flex; align-items:center; gap:12px; margin:12px 0; flex-wrap:wrap">
  <button id="replay-play" type="button"
          style="background:#21262d; color:#c9d1d9; border:1px solid #30363d; border-radius:6px; padding:4px 12px; cursor:pointer">▶ Play</button>
  <input id="replay-scrub" type="range" min="0" max="{{ hist|length - 1 }}" value="{{ hist|length - 1 }}"
         step="1" style="flex:1; min-width:200px">
  <span id="replay-date" class="muted">{{ hist[-1].run_date }}</span>
</div>

<div id="replay-at-wrap">
  {% include "_replay_at.html" %}
</div>

<script>
  (function () {
    const dates = {{ hist | map(attribute="run_date") | list | tojson }};
    const scrub = document.getElementById("replay-scrub");
    const label = document.getElementById("replay-date");
    const playBtn = document.getElementById("replay-play");
    const wrap = document.getElementById("replay-at-wrap");
    let timer = null;        // Play loop (setInterval, paced)
    let fetchTimer = null;   // debounce handle for the scrub server fetch

    // The server round-trip — the expensive part we want to throttle on mobile.
    function fetchAt(i) {
      const d = dates[i];
      fetch("/paper/replay/at?date=" + encodeURIComponent(d))
        .then(function (r) { return r.text(); })
        .then(function (html) { wrap.innerHTML = html; });
    }

    // Scrubbing: update the date label INSTANTLY (the slider thumb already moves natively, so dragging
    // stays live), but DEBOUNCE the server fetch ~180ms so a drag fires one trailing request when the
    // slider settles instead of one per drag-step (the mobile-flaky per-tick round-trip).
    function loadAt(i) {
      label.textContent = dates[i];
      if (fetchTimer) { clearTimeout(fetchTimer); }
      fetchTimer = setTimeout(function () { fetchTimer = null; fetchAt(i); }, 180);
    }

    scrub.addEventListener("input", function () { loadAt(parseInt(scrub.value, 10)); });

    function stop() {
      if (timer) { clearInterval(timer); timer = null; }
      playBtn.textContent = "▶ Play";
    }
    function play() {
      playBtn.textContent = "⏸ Pause";
      if (fetchTimer) { clearTimeout(fetchTimer); fetchTimer = null; }   // drop any pending scrub fetch
      timer = setInterval(function () {
        let i = parseInt(scrub.value, 10);
        if (i >= dates.length - 1) { stop(); return; }
        i += 1;
        scrub.value = i;
        label.textContent = dates[i];
        fetchAt(i);   // Play is already paced (600ms) — fetch directly, no debounce
      }, 600);
    }
    playBtn.addEventListener("click", function () {
      if (timer) { stop(); }
      else {
        if (parseInt(scrub.value, 10) >= dates.length - 1) { scrub.value = 0; label.textContent = dates[0]; fetchAt(0); }
        play();
      }
    });

    // hx-boost: when the nav swaps this page out, kill the Play loop + any pending scrub fetch so a detached
    // page doesn't keep fetching/writing in the background. {once} self-removes after the single nav-away.
    document.body.addEventListener("htmx:beforeSwap", function () {
      stop();
      if (fetchTimer) { clearTimeout(fetchTimer); fetchTimer = null; }
    }, { once: true });
  })();
</script>
{% endif %}
{% endif %}
</div>
{% endblock %}
