<?php include('header.php'); ?>

<script src="https://cdn.plot.ly/plotly-2.30.0.min.js"></script>

<style>
.dash-shell { max-width: 1200px; margin: 16px auto; padding: 0 16px; }
.dash-section { background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: 10px; padding: 16px; margin-bottom: 16px; }
.dash-section h3 { margin: 0 0 12px; font-size: 15px; font-weight: 700; display: flex; align-items: center; gap: 8px; }
.dash-instruments { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; max-height: 180px; overflow-y: auto; }
.dash-instr-btn { padding:4px 10px; font-size:11px; font-weight:600; border-radius:6px; cursor:pointer; border:1px solid var(--color-border); background:transparent; color:var(--color-text-muted); transition:all .15s; white-space:nowrap; display:inline-flex; align-items:center; gap:5px; }
.dash-instr-btn:hover { background:var(--color-bg-surface); color:var(--color-text-primary); }
.dash-instr-btn.active { background:var(--color-accent-blue); border-color:var(--color-accent-blue); color:#fff; }
.dash-instr-btn.no-realtime { opacity:0.4; color:#666; border-color:#333; }
.dash-instr-btn.no-realtime:hover { opacity:0.6; }
.dash-instr-btn .rt-dot { width:6px; height:6px; border-radius:50%; background:#3eb371; box-shadow:0 0 4px #3eb371; flex-shrink:0; }
.dash-instr-btn.no-realtime .rt-dot { background:#555; box-shadow:none; }
.dash-search { width: 100%; padding: 6px 12px; font-size: 13px; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-bg); color: var(--color-text-primary); margin-bottom: 10px; }
.dash-rt-row { display:flex; align-items:center; gap:12px; font-size:12px; color:var(--color-text-muted); margin-bottom:10px; padding:6px 10px; background:var(--color-bg); border:1px solid var(--color-border); border-radius:6px; flex-wrap:wrap; }
.dash-rt-row .rt-pair { display:inline-flex; align-items:center; gap:5px; }
.dash-rt-row .rt-price { color:#3eb371; font-weight:700; font-family:monospace; }
.dash-rt-row .rt-stale { color:#888; font-style:italic; }
.dash-rt-row .rt-err { color:#c0392b; }
.dash-rt-row button { background:transparent; border:1px solid var(--color-border); color:var(--color-text-muted); padding:2px 8px; font-size:11px; border-radius:4px; cursor:pointer; }
.dash-rt-row button:hover { color:var(--color-text-primary); border-color:var(--color-text-muted); }
</style>

<div class="dash-shell">
  <div class="dash-section">
    <h3>Instruments <span id="dash-count" style="font-size:12px;font-weight:400;color:var(--color-text-muted)"></span>
      <span style="margin-left:auto;font-size:11px;font-weight:400;color:var(--color-text-muted)" id="dash-sel-count"></span>
    </h3>
    <input type="text" class="dash-search" id="dash-search" placeholder="Search instruments..." />
    <div class="dash-instruments" id="dash-instruments"><i class="fa-solid fa-spinner fa-spin"></i></div>
  </div>

  <div id="dash-charts"></div>
</div>

<script>
(function(){
  var selectedAssetClass = localStorage.getItem('gk-asset-class') || 'all';
  var allInstruments = [];
  var selected = {};
  var DEFAULT_COUNT = 3;

  window.addEventListener('assetClassChanged', function(e) {
    selectedAssetClass = (e.detail || {}).key || 'all';
    loadInstruments();
  });

  function hasRealtime(r) {
    // A product has real-time access if it's a crypto pair (live via crypto
    // exchanges) OR has a yfinance symbol (live via yfinance.get_snapshot).
    if (r.stype === 'Cryptos') return true;
    if (r.yfinance && r.yfinance !== 'None' && r.yfinance !== 'nan') return true;
    return false;
  }

  function loadInstruments() {
    var el = document.getElementById('dash-instruments');
    el.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
    selected = {};

    fetch('/stealth/referential/get_instruments?columns=canonical,label,stype,yfinance&active=true&asset_class=' + encodeURIComponent(selectedAssetClass))
      .then(function(r){ return r.json(); })
      .then(function(d){
        allInstruments = (d.result || []).map(function(r){
          var item = {
            canonical: r.canonical,
            label: r.label || r.canonical,
            stype: r.stype || '',
            yfinance: r.yfinance || '',
          };
          item.has_realtime = hasRealtime(item);
          return item;
        });
        // Sort: real-time first, then alphabetical by label
        allInstruments.sort(function(a, b){
          if (a.has_realtime !== b.has_realtime) return a.has_realtime ? -1 : 1;
          return a.label.localeCompare(b.label);
        });
        document.getElementById('dash-count').textContent = '(' + allInstruments.length + ')';
        // Default selection: first few real-time instruments
        allInstruments.filter(function(r){ return r.has_realtime; })
          .slice(0, DEFAULT_COUNT)
          .forEach(function(r){ selected[r.canonical] = true; });
        renderInstruments(allInstruments);
        renderCharts();
      })
      .catch(function(e){ el.textContent = 'Failed: ' + e; });
  }

  function renderInstruments(list) {
    var el = document.getElementById('dash-instruments');
    if (!list.length) { el.textContent = 'No instruments'; return; }
    el.innerHTML = list.map(function(r){
      var active = selected[r.canonical] ? ' active' : '';
      var rtClass = r.has_realtime ? '' : ' no-realtime';
      var title = r.canonical + ' — ' + r.stype + (r.has_realtime ? ' (real-time)' : ' (no real-time)');
      return '<button class="dash-instr-btn' + active + rtClass + '" data-canonical="' + r.canonical + '" title="' + title + '">'
        + '<span class="rt-dot"></span>' + r.label + '</button>';
    }).join('');
    el.querySelectorAll('.dash-instr-btn').forEach(function(btn){
      btn.addEventListener('click', function(){
        var c = btn.dataset.canonical;
        if (selected[c]) { delete selected[c]; btn.classList.remove('active'); }
        else { selected[c] = true; btn.classList.add('active'); }
        updateSelCount();
        renderCharts();
      });
    });
    updateSelCount();
  }

  function updateSelCount() {
    document.getElementById('dash-sel-count').textContent = Object.keys(selected).length + ' selected';
  }

  document.getElementById('dash-search').addEventListener('input', function(e){
    var q = e.target.value.toLowerCase();
    renderInstruments(allInstruments.filter(function(r){
      return r.canonical.toLowerCase().indexOf(q) >= 0 || r.label.toLowerCase().indexOf(q) >= 0;
    }));
  });

  function getInstrument(canonical) {
    for (var i = 0; i < allInstruments.length; i++) {
      if (allInstruments[i].canonical === canonical) return allInstruments[i];
    }
    return null;
  }

  function fmtPrice(p) {
    if (p == null || isNaN(p)) return '—';
    if (Math.abs(p) >= 1000) return Number(p).toFixed(2);
    if (Math.abs(p) >= 1)    return Number(p).toFixed(4);
    return Number(p).toPrecision(5);
  }

  function fetchRealtime(canonical, slotId) {
    var slot = document.getElementById(slotId);
    if (!slot) return;
    slot.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> fetching…';
    fetch('/stealth/data/realtime_snapshot/' + encodeURIComponent(canonical))
      .then(function(r){ return r.json(); })
      .then(function(d){
        if (!d || !d.ok) {
          slot.innerHTML = '<span class="rt-err">Live: ' + ((d && d.error) || 'failed') + '</span>';
          return;
        }
        var s = d.snapshot || {};
        var price = s.last_trade != null ? s.last_trade : s.px_last;
        var bid = s.bid, ask = s.ask;
        var ts = s.last_update || '';
        var parts = [];
        parts.push('<span class="rt-pair">live <span class="rt-price">' + fmtPrice(price) + '</span></span>');
        if (bid != null && ask != null) {
          parts.push('<span class="rt-pair">bid/ask <span class="rt-price">' + fmtPrice(bid) + ' / ' + fmtPrice(ask) + '</span></span>');
        }
        parts.push('<span class="rt-pair">via ' + (d.source || '') + '</span>');
        if (ts) parts.push('<span class="rt-stale">' + ts + '</span>');
        if (price == null && bid == null && ask == null) {
          parts = ['<span class="rt-stale">no live quote (market closed?)</span>',
                   '<span class="rt-pair">via ' + (d.source || '') + '</span>'];
        }
        slot.innerHTML = parts.join('');
      })
      .catch(function(e){
        slot.innerHTML = '<span class="rt-err">Live: ' + e + '</span>';
      });
  }

  // Expose for inline onclick handlers
  window.dashFetchRealtime = fetchRealtime;

  function toMlabel(canonical) {
    if (canonical.indexOf('-') >= 0) return canonical.replace(/-/g, '2') + '_1';
    return canonical;
  }

  function normalizeFigure(fig) {
    var payload = fig;
    if (typeof payload === 'string') payload = JSON.parse(payload);
    if (payload && payload.fig) {
      payload = payload.fig;
      if (typeof payload === 'string') payload = JSON.parse(payload);
    }
    return { data: (payload && payload.data) || [], layout: (payload && payload.layout) || {} };
  }

  function plotFigure(url, divId, title) {
    fetch(url)
      .then(function(r){ return r.json(); })
      .then(function(raw){
        var fig = normalizeFigure(raw);
        if (!fig.data.length) { document.getElementById(divId).textContent = 'No data'; return; }
        var layout = Object.assign({}, fig.layout, { autosize: true });
        delete layout.width;
        if (title) layout.title = title;
        Plotly.newPlot(divId, fig.data, layout, { responsive: true });
      })
      .catch(function(e){ document.getElementById(divId).textContent = 'Failed: ' + e; });
  }

  function renderCharts() {
    var container = document.getElementById('dash-charts');
    var keys = Object.keys(selected);
    if (!keys.length) { container.innerHTML = '<div style="color:var(--color-text-muted);font-size:13px;padding:20px">No instruments selected</div>'; return; }

    container.innerHTML = keys.map(function(c){
      var instr = getInstrument(c) || { canonical: c, label: c, has_realtime: false, stype: '' };
      var id = c.replace(/[^a-zA-Z0-9]/g, '_');
      var isCrypto = instr.stype === 'Cryptos';
      var rtRow;
      if (instr.has_realtime) {
        rtRow = '<div class="dash-rt-row" id="rt_row_' + id + '">'
              + '<span id="rt_slot_' + id + '"><span class="rt-stale">live quote — click refresh</span></span>'
              + '<span style="margin-left:auto"></span>'
              + '<button onclick="dashFetchRealtime(\'' + c + '\', \'rt_slot_' + id + '\')">'
              + '<i class="fa-solid fa-arrows-rotate"></i> Refresh</button>'
              + '</div>';
      } else {
        rtRow = '<div class="dash-rt-row"><span class="rt-stale">no real-time source</span></div>';
      }
      // Two-column layout for crypto: close/volumes on the left, live depth chart on the right
      var chartsBlock;
      if (isCrypto) {
        chartsBlock =
          '<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:stretch">'
          + '<div id="daily_cv_' + id + '" style="min-height:450px;background:var(--color-bg);border-radius:8px;padding:8px"><i class="fa-solid fa-spinner fa-spin"></i> Close & Volumes</div>'
          + '<div style="display:flex;flex-direction:column;gap:6px">'
          +   '<div style="display:flex;align-items:center;gap:8px;font-size:11px;color:var(--color-text-muted)">'
          +     '<span>Live depth (hyperliquid)</span>'
          +     '<span style="margin-left:auto"></span>'
          +     '<button onclick="dashRefreshDepth(\'' + c + '\', \'depth_' + id + '\')" style="background:transparent;border:1px solid var(--color-border);color:var(--color-text-muted);padding:2px 8px;font-size:11px;border-radius:4px;cursor:pointer">'
          +       '<i class="fa-solid fa-arrows-rotate"></i> Refresh</button>'
          +   '</div>'
          +   '<div id="depth_' + id + '" style="min-height:380px;background:var(--color-bg);border-radius:8px;padding:8px"><i class="fa-solid fa-spinner fa-spin"></i> Loading depth…</div>'
          + '</div>'
          + '</div>';
      } else {
        chartsBlock = '<div id="daily_cv_' + id + '" style="min-height:450px;background:var(--color-bg);border-radius:8px;padding:8px"><i class="fa-solid fa-spinner fa-spin"></i> Close & Volumes</div>';
      }
      return '<div style="background:var(--color-bg-surface);border:1px solid var(--color-border);border-radius:10px;padding:16px;margin-bottom:16px">'
        + '<h4 style="margin:0 0 12px;font-size:14px;font-weight:700;color:var(--color-text-primary)">'
        + instr.label + ' <span style="font-weight:400;color:var(--color-text-muted);font-size:12px">(' + c + ')</span></h4>'
        + rtRow
        + chartsBlock
        + '</div>';
    }).join('');

    keys.forEach(function(canonical){
      var instr = getInstrument(canonical) || { label: canonical, stype: '' };
      var id = canonical.replace(/[^a-zA-Z0-9]/g, '_');
      var ml = toMlabel(canonical);

      // Close & Volumes (old endpoint with per-exchange lines, zoom, stacked volumes)
      plotFigure('/stealth/monitoring/plot_close_volumes/' + encodeURIComponent(ml), 'daily_cv_' + id, instr.label + ' — Close & Volumes');

      // Auto-fetch live quote on first render for instruments that have real-time
      if (instr.has_realtime) {
        fetchRealtime(canonical, 'rt_slot_' + id);
      }

      // Auto-fetch the live depth chart for crypto instruments
      if (instr.stype === 'Cryptos') {
        plotFigure('/stealth/monitoring/depth_chart/' + encodeURIComponent(canonical) + '?exchange=hyperliquid&depth=40', 'depth_' + id, null);
      }
    });
  }

  // Expose depth refresh for inline onclick handlers
  window.dashRefreshDepth = function(canonical, divId) {
    document.getElementById(divId).innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Refreshing depth…';
    plotFigure('/stealth/monitoring/depth_chart/' + encodeURIComponent(canonical) + '?exchange=hyperliquid&depth=40', divId, null);
  };

  loadInstruments();
})();
</script>

<?php include('footer.php');?>
