function duplicateFileReport(incoming = []) {
    const used = new Set(files.map((item) => normalizedFileName(item.displayName)));
    const duplicates = [];
    const unique = [];
    incoming.forEach((item) => {
        const key = normalizedFileName(item.displayName);
        if (used.has(key)) {
            duplicates.push(item);
            return;
        }
        used.add(key);
        unique.push(item);
    });
    return { unique, duplicates };
}

function addFiles(fileList) {
    if (!uploadsEnabled) {
        showToast("Guest uploads are disabled.", "warning");
        return;
    }
    if (uploadLocked) {
        showToast("This box is sealed. Clear it to create a fresh upload.", "warning");
        return;
    }
    const incoming = Array.from(fileList || []).map((file) => makeQueuedFile(file));
    if (!incoming.length) return;

    const { unique, duplicates } = duplicateFileReport(incoming);
    if (unique.length) {
        files.push(...unique);
        setShareUrl("");
        renderFiles();
        const warning = quotaWarningMessage();
        if (warning) showWarningDialog("Quota warning", warning);
    }
    if (duplicates.length) showDuplicateDialog(duplicates);

    if (unique.length) setStatus(`${unique.length} file${unique.length === 1 ? "" : "s"} added to queue`);
    if (duplicates.length && !unique.length) setStatus(`${duplicates.length} duplicate file${duplicates.length === 1 ? "" : "s"} need your choice`);
}

function showDuplicateDialog(duplicates) {
    pendingDuplicateFiles = duplicates;
    const list = duplicates.map((item) => `<li><strong>${htmlEscape(item.displayName)}</strong> <span>${formatBytes(item.file.size)}</span></li>`).join("");
    showTemplatePopup("Duplicate file names", "duplicate", { list })
        .then(() => document.querySelector("#duplicate-append")?.focus());
    showToast("Duplicate names found. Choose skip or append numbers.", "warning");
}

function appendPendingDuplicates() {
    if (!pendingDuplicateFiles.length) return;
    const used = new Set(files.map((item) => normalizedFileName(item.displayName)));
    pendingDuplicateFiles.forEach((item) => {
        item.displayName = nextIncrementedFileName(item.displayName, used);
        files.push(item);
    });
    const count = pendingDuplicateFiles.length;
    pendingDuplicateFiles = [];
    closeDoc();
    setShareUrl("");
    renderFiles();
    showToast("Duplicate files added with numbered names.", "info");
    setStatus(`${count} duplicate file${count === 1 ? "" : "s"} added with numbered names`);
}

function removeFile(index) {
    if (uploadLocked) {
        showToast("Box already created. Clear it before editing the queue.", "warning");
        return;
    }
    const [removed] = files.splice(index, 1);
    if (removed?.previewURL) URL.revokeObjectURL(removed.previewURL);
    setShareUrl("");
    renderFiles();
    setStatus("File removed from queue");
}

function clearQueue() {
    files.forEach((item) => {
        if (item.previewURL) URL.revokeObjectURL(item.previewURL);
    });
    files = [];
    pendingDuplicateFiles = [];
    uploadLocked = false;
    completedImpactKeys = new Set();
    overallImpactDone = false;
    stopStatusAnimation();
    setBoxOptionsLocked(false);
    setShareUrl("");
    if (el.fileInput) {
        el.fileInput.value = "";
        el.fileInput.disabled = !uploadsEnabled;
    }
    el.dropzone?.classList.remove("is-locked");
    renderFiles();
    setStatus(uploadsEnabled ? "Queue cleared" : "Guest uploads are disabled");
    showToast("Queue cleared.");
}

function confirmClearQueue() {
    if (!files.length && !shareUrl) {
        showToast("Nothing to clear.");
        return;
    }
    showTemplatePopup("Clear WarpBox?", "clear")
        .then(() => document.querySelector("#confirm-clear-no")?.focus());
}
