/* ───────────────────────────────────────────────────────────────────────────
   Wivexx Performance HUD — always-on-top hardware widget, control-room styled.
   Fed live telemetry (wivexx_sysmon) via the bridge: setData(snapshot).
   ─────────────────────────────────────────────────────────────────────────── */
(function () {
  "use strict";
  let _pyReady = false;
  const _queue = [];
  function py(method) {
    const args = Array.prototype.slice.call(arguments, 1);
    const run = () => { try { return window.pywebview.api[method].apply(null, args); } catch (e) {} };
    if (_pyReady && window.pywebview && window.pywebview.api) return run();
    _queue.push(run); return undefined;
  }
  function flush() { _pyReady = true; while (_queue.length) { try { _queue.shift()(); } catch (e) {} } }
  const $ = (id) => document.getElementById(id);

  const ALL = ["cpu", "gpu", "vram", "ram", "disk", "net", "speed", "fps"];
  const LABEL = { cpu: "CPU", gpu: "GPU", vram: "VRAM", ram: "RAM", disk: "DISK", net: "NET", speed: "SPEED", fps: "FPS" };
  const NAMES = { cpu: "CPU usage + temp", gpu: "GPU usage + temp", vram: "GPU memory",
    ram: "System RAM", disk: "Disk (C:)", net: "Live throughput ↓↑ (MB/s)", speed: "Internet speed (tap to test)",
    fps: "Game FPS — needs MSI Afterburner / RTSS running" };
  let metrics = ["cpu", "gpu", "vram", "ram", "net", "speed"];
  let lastSnap = {};

  function loadColor(f) {
    if (f == null) return "var(--stone-dim)";
    if (f >= 0.9) return "var(--danger)";
    if (f >= 0.7) return "var(--amber)";
    return "var(--volt)";
  }
  const pct = (v) => (v == null ? null : Math.max(0, Math.min(1, v / 100)));

  function metric(key, s) {
    const g = s.gpu || {}, c = s.cpu || {}, r = s.ram || {}, n = s.net || {}, d = s.disk || {};
    const t = (v, u) => (v == null ? "—" : v.toFixed(0) + (u || ""));
    if (key === "cpu") return { bar: 1, frac: pct(c.pct), main: t(c.pct, "%"), sub: c.temp_c != null ? t(c.temp_c, "°C") : "—" };
    if (key === "gpu") return { bar: 1, frac: pct(g.pct), main: t(g.pct, "%"), sub: g.temp_c != null ? t(g.temp_c, "°C") : "—" };
    if (key === "vram") return { bar: 1, frac: pct(g.mem_pct), main: t(g.mem_pct, "%"),
      sub: (g.mem_used_mb && g.mem_total_mb) ? (g.mem_used_mb / 1024).toFixed(1) + "/" + (g.mem_total_mb / 1024).toFixed(0) + "G" : "—" };
    if (key === "ram") return { bar: 1, frac: pct(r.pct), main: t(r.pct, "%"),
      sub: (r.used_gb && r.total_gb) ? r.used_gb.toFixed(0) + "/" + r.total_gb.toFixed(0) + "G" : "—" };
    if (key === "disk") return { bar: 1, frac: pct(d.pct), main: t(d.pct, "%"), sub: "C:" };
    if (key === "net") {
      // v1.56: ADAPTIVE units so the rate always reads clearly — KB/s < MB/s < GB/s.
      // down_kbps / up_kbps are KB/s (binary: 1 MB/s = 1024 KB/s).
      const fmt = (k) => {
        if (k == null) return "—";
        if (k < 1024) return (k >= 10 ? k.toFixed(0) : k.toFixed(1)) + " KB/s";
        const m = k / 1024;
        if (m < 1024) return (m >= 10 ? m.toFixed(0) : m.toFixed(1)) + " MB/s";
        const g = m / 1024;
        return (g >= 10 ? g.toFixed(0) : g.toFixed(2)) + " GB/s";
      };
      return { bar: 0, main: "↓" + fmt(n.down_kbps), sub: "↑" + fmt(n.up_kbps) };
    }
    if (key === "speed") {
      const sp = s.speed || {};
      if (sp.down_mbps != null) return { bar: 0, click: 1, main: "↓" + sp.down_mbps + "M", sub: sp.up_mbps != null ? "↑" + sp.up_mbps + "M" : "" };
      return { bar: 0, click: 1, main: "—", sub: "tap to test" };
    }
    if (key === "fps") return { bar: 0, main: (s.fps ? s.fps.toFixed(0) : "—"), sub: s.fps ? "fps" : "RTSS" };
    return { bar: 0, main: "—", sub: "" };
  }

  function render() {
    const body = $("body"); if (!body) return;
    const html = metrics.map((k) => {
      const m = metric(k, lastSnap);
      if (m.bar) {
        const w = m.frac == null ? 0 : Math.round(m.frac * 100);
        return '<div class="row"><span class="lab">' + LABEL[k] + "</span>" +
          '<div class="track"><div class="fill" style="width:' + w + "%;background:" + loadColor(m.frac) + '"></div></div>' +
          '<span class="val"><span class="m">' + m.main + '</span><span class="s">' + m.sub + "</span></span></div>";
      }
      return '<div class="row text' + (m.click ? " tap" : "") + '"' + (m.click ? ' data-act="' + k + '"' : "") + '>' +
        '<span class="lab">' + LABEL[k] + "</span>" +
        '<span class="wide"><span>' + m.main + '</span><span class="up">' + m.sub + "</span></span></div>";
    }).join("");
    body.innerHTML = html || '<div class="row text"><span class="lab"></span><span class="wide soon">no metrics</span></div>';
    const sr = body.querySelector('[data-act="speed"]');
    if (sr) sr.addEventListener("click", () => {
      sr.querySelector(".up").textContent = "testing…"; py("speedtest");
    });
    fit();
  }

  // resize the OS window to hug the content (so no awkward empty space)
  let lastH = 0;
  function fit() {
    requestAnimationFrame(() => {
      const h = Math.ceil(document.body.scrollHeight);
      if (h && Math.abs(h - lastH) > 2) { lastH = h; py("resize", h); }
    });
  }

  function renderCog() {
    const cog = $("cog");
    cog.innerHTML = ALL.map((k) => {
      const on = metrics.indexOf(k) >= 0;
      return '<div class="opt' + (on ? "" : " off") + '" data-k="' + k + '">' +
        '<span class="tick">' + (on ? "✓" : "") + "</span>" + NAMES[k] + "</div>";
    }).join("");
    cog.querySelectorAll(".opt").forEach((el) => el.addEventListener("click", () => {
      const k = el.getAttribute("data-k");
      const i = metrics.indexOf(k);
      if (i >= 0) metrics.splice(i, 1); else metrics.push(k);
      metrics = ALL.filter((m) => metrics.indexOf(m) >= 0);
      if (!metrics.length) metrics = [k];
      py("set_metrics", metrics);
      renderCog(); render();
    }));
  }

  function flash(msg) {
    const f = $("flash");
    f.textContent = "⚡ " + msg; f.classList.add("on"); fit();
    clearTimeout(flash._t);
    flash._t = setTimeout(() => { f.classList.remove("on"); fit(); }, 5000);
  }

  // ── bridge surface ──
  window.wivexxPerf = {
    setData: (snap) => { lastSnap = snap || {}; render(); },
    setMetrics: (list) => { if (Array.isArray(list) && list.length) { metrics = ALL.filter((m) => list.indexOf(m) >= 0); render(); renderCog(); } },
  };

  function wireDrag() {
    let dx = 0, dy = 0, dragging = false;
    const bar = $("bar");
    bar.addEventListener("mousedown", (e) => {
      if (e.button !== 0 || e.target.closest("button")) return;
      dx = e.screenX; dy = e.screenY; dragging = false; e.preventDefault();
    });
    document.addEventListener("mousemove", (e) => {
      if (e.buttons === 0 || dragging) return;
      if (Math.abs(e.screenX - dx) > 4 || Math.abs(e.screenY - dy) > 4) { dragging = true; py("start_drag"); }
    });
    document.addEventListener("mouseup", () => { dragging = false; });
  }

  function boot() {
    $("x").addEventListener("click", () => py("close"));
    $("cogbtn").addEventListener("click", () => $("cog").classList.toggle("open"));
    $("opt").addEventListener("click", () => {
      flash("optimizing…");
      const r = py("optimize");
      const done = (msg) => flash(msg || "done");
      if (r && r.then) r.then(done).catch(() => flash("optimize failed"));
    });
    document.addEventListener("click", (e) => {
      if (!e.target.closest("#cog") && e.target.id !== "cogbtn") $("cog").classList.remove("open");
    });
    wireDrag();
    renderCog();
    py("ready");
  }
  if (window.pywebview && window.pywebview.api) { _pyReady = true; }
  window.addEventListener("pywebviewready", flush);
  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", boot);
  else boot();
})();
