/**
 * Client runtime for `<div data-uploader>` elements — drag-and-drop + file
 * input, per-file progress bars, and success/failed states. Injected by
 * `collectScripts` only on pages that contain `data-uploader` (same mechanism as
 * `validate.js`). Self-contained: it injects its own themed stylesheet (using
 * `--wire-*` tokens) and posts each file via XHR so upload progress is live.
 *
 * Markup it enhances (also a valid no-JS `<form>` fallback if you wrap it):
 *   <div data-uploader="public" data-endpoint="/api/upload"
 *        data-accept="image/*" data-max="10000000" data-multiple></div>
 *
 * Events dispatched on the element (bubble):
 *   wrnexus:upload        detail: { file, result: { key, url, name, size, type } }
 *   wrnexus:upload-error  detail: { file, error }
 *
 * NOTE: written with single/double quotes + string concatenation only — no
 * backticks and no ${...}, so it embeds safely in the exported template string.
 */
export const UPLOAD_JS_HREF = "/__wrnexus/uploader.js";

export const UPLOAD_RUNTIME = `
(function () {
  if (typeof document === "undefined") return;
  var CSRF_COOKIE = "wire-csrf";

  var CSS =
    ".wire-uploader{display:block}" +
    ".wire-uploader-zone{display:flex;align-items:center;justify-content:center;text-align:center;" +
      "min-height:8rem;padding:1.25rem;border:2px dashed var(--wire-border,#cbd5e1);border-radius:12px;" +
      "background:var(--wire-surface,transparent);color:var(--wire-muted,#64748b);cursor:pointer;" +
      "transition:border-color .15s ease,background-color .15s ease;position:relative}" +
    ".wire-uploader-zone:hover,.wire-uploader-zone:focus-visible{border-color:var(--wire-brand,#3f7dff);outline:none}" +
    ".wire-uploader-zone.is-drag{border-color:var(--wire-brand,#3f7dff);background:color-mix(in oklab,var(--wire-brand,#3f7dff) 8%,transparent)}" +
    ".wire-uploader-prompt{font-size:.9rem;pointer-events:none}" +
    ".wire-uploader-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}" +
    ".wire-uploader-list{list-style:none;margin:.75rem 0 0;padding:0;display:flex;flex-direction:column;gap:.5rem}" +
    ".wire-uploader-item{display:grid;grid-template-columns:1fr auto;gap:.15rem .75rem;align-items:center;" +
      "font-size:.82rem;padding:.5rem .7rem;border:1px solid var(--wire-border,#e2e8f0);border-radius:8px}" +
    ".wire-uploader-name{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--wire-text,#0f172a)}" +
    ".wire-uploader-meta{color:var(--wire-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
    ".wire-uploader-bar{grid-column:1/-1;height:5px;border-radius:999px;background:var(--wire-border,#e2e8f0);overflow:hidden}" +
    ".wire-uploader-fill{height:100%;width:0;border-radius:999px;background:var(--wire-brand,#3f7dff);transition:width .15s ease}" +
    ".wire-uploader-status{grid-column:1/-1;font-size:.75rem;color:var(--wire-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
    ".wire-uploader-item.is-done .wire-uploader-fill{background:var(--wire-success,#16a34a)}" +
    ".wire-uploader-item.is-done .wire-uploader-status{color:var(--wire-success,#16a34a)}" +
    ".wire-uploader-item.is-error .wire-uploader-fill{background:var(--wire-danger,#dc2626)}" +
    ".wire-uploader-item.is-error .wire-uploader-status{color:var(--wire-danger,#dc2626)}";

  function injectCss() {
    if (document.getElementById("wire-uploader-css")) return;
    var s = document.createElement("style");
    s.id = "wire-uploader-css";
    s.textContent = CSS;
    document.head.appendChild(s);
  }

  function cookie(name) {
    var m = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
    return m ? decodeURIComponent(m[1]) : "";
  }
  function el(tag, cls, text) {
    var e = document.createElement(tag);
    if (cls) e.className = cls;
    if (text != null) e.textContent = text;
    return e;
  }
  function fmt(n) {
    if (n < 1024) return n + " B";
    if (n < 1048576) return (n / 1024).toFixed(1) + " KB";
    return (n / 1048576).toFixed(1) + " MB";
  }
  function accepts(accept, file) {
    var list = (accept || "").split(",").map(function (s) { return s.trim().toLowerCase(); }).filter(Boolean);
    if (!list.length) return true;
    var type = (file.type || "").toLowerCase();
    var name = (file.name || "").toLowerCase();
    var ext = name.indexOf(".") >= 0 ? name.slice(name.lastIndexOf(".")) : "";
    return list.some(function (rule) {
      if (rule.charAt(0) === ".") return rule === ext;
      if (rule.slice(-2) === "/*") return type.indexOf(rule.slice(0, -1)) === 0;
      return rule === type;
    });
  }

  function setup(root) {
    if (root.__wrnexusUploader) return;
    root.__wrnexusUploader = true;

    var endpoint = root.getAttribute("data-endpoint") || "/api/upload";
    var multipleAttr = root.getAttribute("data-multiple");
    var multiple = root.hasAttribute("data-multiple") && multipleAttr !== "false";
    var accept = root.getAttribute("data-accept") || "";
    var maxBytes = parseInt(root.getAttribute("data-max") || "0", 10) || 0;
    var field = root.getAttribute("data-field") || (multiple ? "files" : "file");
    var invalidate = String(root.getAttribute("data-invalidate") || "")
      .split(",")
      .map(function (tag) { return tag.trim(); })
      .filter(Boolean);
    var promptText = root.getAttribute("data-label") || "Drag files here or click to browse";

    root.classList.add("wire-uploader");
    var zone = el("div", "wire-uploader-zone");
    zone.setAttribute("role", "button");
    zone.setAttribute("tabindex", "0");
    zone.appendChild(el("div", "wire-uploader-prompt", promptText));
    var input = document.createElement("input");
    input.type = "file";
    input.className = "wire-uploader-input";
    if (multiple) input.multiple = true;
    if (accept) input.accept = accept;
    zone.appendChild(input);
    var listEl = el("ul", "wire-uploader-list");
    root.appendChild(zone);
    root.appendChild(listEl);

    zone.addEventListener("keydown", function (e) {
      if (e.key === "Enter" || e.key === " ") { e.preventDefault(); input.click(); }
    });
    ["dragenter", "dragover"].forEach(function (ev) {
      zone.addEventListener(ev, function (e) { e.preventDefault(); zone.classList.add("is-drag"); });
    });
    ["dragleave", "drop"].forEach(function (ev) {
      zone.addEventListener(ev, function (e) { e.preventDefault(); zone.classList.remove("is-drag"); });
    });
    zone.addEventListener("drop", function (e) {
      if (e.dataTransfer && e.dataTransfer.files) handle(e.dataTransfer.files);
    });
    input.addEventListener("change", function () {
      if (input.files) handle(input.files);
      input.value = "";
    });

    function handle(files) {
      var arr = Array.prototype.slice.call(files);
      if (!multiple) arr = arr.slice(0, 1);
      arr.forEach(uploadOne);
    }

    function row(file) {
      var li = el("li", "wire-uploader-item");
      li.appendChild(el("span", "wire-uploader-name", file.name));
      li.appendChild(el("span", "wire-uploader-meta", fmt(file.size)));
      var bar = el("div", "wire-uploader-bar");
      var fill = el("div", "wire-uploader-fill");
      bar.appendChild(fill);
      li.appendChild(bar);
      var status = el("span", "wire-uploader-status", "");
      li.appendChild(status);
      listEl.appendChild(li);
      return { li: li, fill: fill, status: status };
    }

    function uploadOne(file) {
      var ui = row(file);
      if (maxBytes && file.size > maxBytes) return fail(ui, "Too large (max " + fmt(maxBytes) + ")", file);
      if (!accepts(accept, file)) return fail(ui, "Type not allowed", file);

      var fd = new FormData();
      fd.append(field, file, file.name);
      var xhr = new XMLHttpRequest();
      xhr.open("POST", endpoint, true);
      var token = cookie(CSRF_COOKIE);
      if (token) xhr.setRequestHeader("x-csrf-token", token);
      xhr.upload.addEventListener("progress", function (e) {
        if (e.lengthComputable) {
          var pct = Math.round((e.loaded / e.total) * 100);
          ui.fill.style.width = pct + "%";
          ui.status.textContent = pct + "%";
        }
      });
      xhr.addEventListener("load", function () {
        var data = null;
        try { data = JSON.parse(xhr.responseText); }
        catch (error) { console.warn("[wrnexus:uploader] upload response was not valid JSON", error); }
        if (xhr.status >= 200 && xhr.status < 300 && data && data.ok) {
          done(ui, (data.files && data.files[0]) || null, file);
        } else {
          fail(ui, (data && data.error) || ("Upload failed (" + xhr.status + ")"), file);
        }
      });
      xhr.addEventListener("error", function () { fail(ui, "Network error", file); });
      xhr.send(fd);
    }

    function done(ui, info, file) {
      ui.li.classList.remove("is-error");
      ui.li.classList.add("is-done");
      ui.fill.style.width = "100%";
      ui.status.textContent = "\\u2713 Uploaded";
      root.dispatchEvent(new CustomEvent("wrnexus:upload", { bubbles: true, detail: { file: file, result: info } }));
      if (invalidate.length) {
        window.dispatchEvent(new CustomEvent("wrnexus:cache:invalidate", {
          detail: { tags: invalidate, source: "uploader", file: file, result: info }
        }));
      }
    }
    function fail(ui, msg, file) {
      ui.li.classList.add("is-error");
      ui.status.textContent = "\\u2717 " + msg;
      root.dispatchEvent(new CustomEvent("wrnexus:upload-error", { bubbles: true, detail: { file: file, error: msg } }));
    }
  }

  function init() {
    injectCss();
    var nodes = document.querySelectorAll("[data-uploader]");
    for (var i = 0; i < nodes.length; i++) setup(nodes[i]);
  }
  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
  else init();
})();
`;
