/* Per-device program I/O — assembled into each form-factor page (the thin widget).
   Uses the engine codec (patchToSetup / setupToPatch / codeToSetlist) for decode + lint.
   Host page provides: window.currentProgramString() and window.loadProgramString(plain).
   Exposes window.progRefresh() — call it after the device's program changes. When the
   page is embedded it posts {type:'varasys-prog'} to the parent instead of touching the box.
   (Specs / dimensions / BOM live on the separate info-<device>.html page, not here.)
   Defers to DOM-ready so the box is found wherever it sits on the page. */
(function () {
  var embedded = document.documentElement.dataset.embed === "1";
  var box, msg, editing = false;
  function setMsg(t, ok) { if (!msg) return; msg.textContent = t || ""; msg.classList.toggle("ok", !!ok && !!t); msg.classList.toggle("bad", !ok && !!t); }
  function lint(text) {
    text = (text || "").trim(); if (!text) return { ok: false, msg: "empty" };
    var m = text.match(/[#?&](p|sl)=([^&\s]+)/), kind = null, payload = text;
    if (m) { kind = m[1]; try { payload = decodeURIComponent(m[2]); } catch (e) { payload = m[2]; } }
    var b64 = /^[A-Za-z0-9_-]{12,}$/.test(payload) && !/[;:]/.test(payload);
    try {
      if (kind === "sl" || (kind !== "p" && b64)) {
        var sl = codeToSetlist(payload); if (!sl.items || !sl.items.length) throw new Error("set-list code has no items");
        return { ok: true, plain: setupToPatch(sl.items[0]), msg: "decoded set list “" + sl.title + "” — item 1" };
      }
      var s = patchToSetup(payload); if (!s.lanes.length) throw new Error("no lanes — try e.g. kick:4");
      return { ok: true, plain: setupToPatch(s), msg: s.lanes.length + " lane" + (s.lanes.length > 1 ? "s" : "") + " · " + s.bpm + " BPM" };
    } catch (e) { return { ok: false, msg: "✗ " + e.message }; }
  }
  function doLoad() {
    var r = lint(box.value);
    if (!r.ok) { box.classList.add("err"); setMsg(r.msg, false); return; }
    box.classList.remove("err"); box.value = r.plain; setMsg("✓ " + r.msg, true);
    try { if (window.loadProgramString) window.loadProgramString(r.plain); } catch (e) { setMsg("✗ " + e.message, false); }
  }
  // report the current program: to the parent when embedded, else into the box.
  // No-op on pages without a program hook (e.g. panel-based Teacher/Player).
  window.progRefresh = function () {
    if (!window.currentProgramString) return;
    var p = ""; try { p = window.currentProgramString(); } catch (e) {}
    if (embedded) { try { parent.postMessage({ type: "varasys-prog", patch: p }, "*"); } catch (e) {} return; }
    if (box && !editing) { box.value = p; setMsg("", true); }
  };
  function init() {
    box = document.getElementById("dProg"); msg = document.getElementById("dProgMsg");
    if (box) {
      box.addEventListener("focus", function () { editing = true; });
      box.addEventListener("blur", function () { editing = false; });
      box.addEventListener("input", function () { box.classList.remove("err"); });
      box.addEventListener("keydown", function (e) { if (e.key === "Enter") { e.preventDefault(); doLoad(); } });
      var loadBtn = document.getElementById("dProgLoad"); if (loadBtn) loadBtn.addEventListener("click", doLoad);
      var copyBtn = document.getElementById("dProgCopy"); if (copyBtn) copyBtn.addEventListener("click", function () {
        try { navigator.clipboard.writeText(box.value); copyBtn.textContent = "Copied!"; setTimeout(function () { copyBtn.textContent = "Copy"; }, 1200); } catch (e) { box.select(); }
      });
    }
    window.progRefresh();
  }
  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init); else init();
})();
