(function () {
  const form = document.querySelector("#upload-form");
  const dropZone = document.querySelector(".drop-zone");
  const fileInput = document.querySelector("#file-input");
  const fileSummary = document.querySelector("#file-summary");
  const progress = document.querySelector("#upload-progress");
  const uploadStatus = document.querySelector("#upload-status");
  const result = document.querySelector("#upload-result");
  const resultMeta = document.querySelector("#result-meta");
  const resultList = document.querySelector("#result-list");
  const uploadQueue = document.querySelector("#upload-queue");
  const totalProgressBar = document.querySelector("#total-progress-bar");
  const copyURL = document.querySelector("#copy-url");
  const openBox = document.querySelector("#open-box");
  const manageLink = document.querySelector("#manage-link");

  if (!form || !dropZone || !fileInput) {
    return;
  }

  // Remember the last-chosen expiry across uploads (per browser).
  const expirySelect = form.querySelector("[data-expiry-select]");
  if (expirySelect) {
    const EXPIRY_KEY = "warpbox-expiry";
    let saved = null;
    try {
      saved = localStorage.getItem(EXPIRY_KEY);
    } catch (e) {
      saved = null;
    }
    if (saved && expirySelect.querySelector('option[value="' + saved + '"]')) {
      expirySelect.value = saved;
    }
    expirySelect.addEventListener("change", () => {
      try {
        localStorage.setItem(EXPIRY_KEY, expirySelect.value);
      } catch (e) {
        /* ignore persistence failures */
      }
    });
  }

  let latestBoxURL = "";
  let selectedFiles = [];

  ["dragenter", "dragover"].forEach((eventName) => {
    dropZone.addEventListener(eventName, (event) => {
      event.preventDefault();
      dropZone.classList.add("is-dragging");
    });
  });

  ["dragleave", "drop"].forEach((eventName) => {
    dropZone.addEventListener(eventName, (event) => {
      event.preventDefault();
      dropZone.classList.remove("is-dragging");
    });
  });

  dropZone.addEventListener("drop", (event) => {
    if (event.dataTransfer && event.dataTransfer.files.length > 0) {
      fileInput.files = event.dataTransfer.files;
      updateSelectedState(event.dataTransfer.files);
    }
  });

  fileInput.addEventListener("change", () => updateSelectedState(fileInput.files));

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    if (!fileInput.files || fileInput.files.length === 0) {
      updateStatus("Choose at least one file first.");
      return;
    }

    const submit = form.querySelector("button[type='submit']");
    const formData = new FormData(form);
    selectedFiles = Array.from(fileInput.files);
    renderQueue(selectedFiles, "queued");
    setLoading(true, submit);

    try {
      const payload = await uploadWithProgress(form.action, formData, selectedFiles);
      renderResult(payload);
      form.reset();
      updateSelectedState([]);
    } catch (error) {
      updateStatus(error.message || "Upload failed");
    } finally {
      setLoading(false, submit);
    }
  });

  if (copyURL) {
    copyURL.addEventListener("click", () => {
      window.Warpbox.copyText(latestBoxURL, copyURL, "Copied");
    });
  }

  function updateSelectedState(files) {
    selectedFiles = Array.from(files || []);
    const count = selectedFiles.length || 0;
    const title = dropZone.querySelector(".drop-title");
    if (title) {
      title.textContent = count === 0 ? "Drop files to upload" : count === 1 ? "1 file selected" : `${count} files selected`;
    }
    if (fileSummary) {
      fileSummary.textContent = count === 0 ? "Choose one or more files to begin." : `${count} file${count === 1 ? "" : "s"} ready.`;
    }
    if (count > 0) {
      renderQueue(selectedFiles, "queued");
    } else if (uploadQueue) {
      uploadQueue.hidden = true;
      uploadQueue.replaceChildren();
    }
  }

  function setLoading(isLoading, submit) {
    if (progress) {
      progress.hidden = !isLoading;
    }
    if (submit) {
      submit.disabled = isLoading;
      submit.textContent = isLoading ? "Uploading..." : "Upload files";
    }
    updateStatus(isLoading ? "Transferring files..." : "");
    setTotalProgress(isLoading ? 0 : 100);
  }

  function updateStatus(message) {
    if (uploadStatus) {
      uploadStatus.textContent = message;
    }
  }

  function renderResult(payload) {
    if (!result || !resultList || !resultMeta || !openBox) {
      return;
    }

    latestBoxURL = payload.boxUrl;
    result.hidden = false;
    openBox.href = payload.boxUrl;
    resultMeta.textContent = `${payload.files.length} file${payload.files.length === 1 ? "" : "s"} · expires ${window.Warpbox.formatDate(payload.expiresAt)}`;
    if (manageLink) {
      const anchor = manageLink.querySelector("a");
      manageLink.hidden = !payload.manageUrl;
      if (anchor && payload.manageUrl) {
        anchor.href = payload.manageUrl;
      }
    }

    resultList.replaceChildren();
    payload.files.forEach((file) => {
      resultList.append(createFileRow({
        name: file.name,
        meta: `${file.size} · ${file.url}`,
        progress: 100,
        status: "complete",
      }));
    });
  }

  function uploadWithProgress(url, formData, files) {
    return new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      request.open("POST", url);
      request.setRequestHeader("Accept", "application/json");

      request.upload.addEventListener("progress", (event) => {
        if (!event.lengthComputable) {
          updateStatus("Uploading...");
          return;
        }
        const percent = Math.round((event.loaded / event.total) * 100);
        updateStatus(`${percent}%`);
        setTotalProgress(percent);
        setFileProgress(files, percent);
      });

      request.addEventListener("load", () => {
        let payload = {};
        try {
          payload = JSON.parse(request.responseText || "{}");
        } catch (error) {
          reject(new Error("Upload response could not be read"));
          return;
        }
        if (request.status < 200 || request.status >= 300) {
          reject(new Error(payload.error || "Upload failed"));
          return;
        }
        setTotalProgress(100);
        setFileProgress(files, 100);
        resolve(payload);
      });

      request.addEventListener("error", () => reject(new Error("Network error during upload")));
      request.addEventListener("abort", () => reject(new Error("Upload aborted")));
      request.send(formData);
    });
  }

  function renderQueue(files, status) {
    if (!uploadQueue) {
      return;
    }
    uploadQueue.hidden = files.length === 0;
    uploadQueue.replaceChildren();
    files.forEach((file) => {
      uploadQueue.append(createFileRow({
        name: file.name,
        meta: window.Warpbox.formatBytes(file.size),
        progress: status === "queued" ? 0 : 100,
        status,
      }));
    });
  }

  function createFileRow(file) {
    const row = document.createElement("div");
    row.className = "result-item upload-file-row";
    row.dataset.fileName = file.name;

    const body = document.createElement("span");
    const name = document.createElement("strong");
    name.className = "file-name";
    name.textContent = file.name;
    name.title = file.name;
    const meta = document.createElement("code");
    meta.textContent = file.meta;
    body.append(name, meta);

    const side = document.createElement("div");
    side.className = "file-progress-side";
    const percent = document.createElement("span");
    percent.className = "file-progress-percent";
    percent.textContent = `${file.progress}%`;
    const bar = document.createElement("div");
    bar.className = "progress file-progress";
    const fill = document.createElement("span");
    fill.style.transform = `scaleX(${file.progress / 100})`;
    bar.append(fill);
    side.append(percent, bar);

    row.append(body, side);
    return row;
  }

  function setTotalProgress(percent) {
    if (totalProgressBar) {
      totalProgressBar.style.transform = `scaleX(${Math.max(0, Math.min(100, percent)) / 100})`;
    }
  }

  function setFileProgress(files, totalPercent) {
    if (!uploadQueue) {
      return;
    }
    const count = files.length || 1;
    const completedFloat = (Math.max(0, Math.min(100, totalPercent)) / 100) * count;
    uploadQueue.querySelectorAll(".upload-file-row").forEach((row, index) => {
      const progress = Math.max(0, Math.min(100, Math.round((completedFloat - index) * 100)));
      const percent = row.querySelector(".file-progress-percent");
      const fill = row.querySelector(".file-progress span");
      if (percent) {
        percent.textContent = `${progress}%`;
      }
      if (fill) {
        fill.style.transform = `scaleX(${progress / 100})`;
      }
    });
  }
})();
