const boxPanel = document.querySelector(".box-panel[data-box-id]");
const boxStatus = document.querySelector(".box-statusbar span:first-child");
const boxAddress = document.querySelector("#box-address");
const boxExpiryMeta = document.querySelector(".box-meta[data-expires-at]");
const boxExpiryText = document.querySelector("#box-expiry-text");
const contextMenu = document.querySelector("#box-context-menu");
const docPopup = document.querySelector("#doc-popup");
const docPopupTitle = document.querySelector("#doc-popup-title");
const docPopupBody = document.querySelector("#doc-popup-body");
const docPopupClose = document.querySelector("#doc-popup-close");
const modalBackdrop = document.querySelector("#modal-backdrop");
const toast = document.querySelector("#toast");
const zipOnly = boxPanel && boxPanel.dataset.zipOnly === "true";

let contextFile = null;
let lastStatusSignature = "";

const htmlEscape = window.WarpBoxUI.htmlEscape;

function showToast(message, type = "info") {
    window.WarpBoxUI.toast(message, type, { target: toast });
}

function openPopup(title, html, options = {}) {
    window.WarpBoxUI.openPopup(title, html, {
        ...options,
        popup: docPopup,
        title: docPopupTitle,
        body: docPopupBody,
        backdrop: modalBackdrop,
    });
}

function closePopup() {
    window.WarpBoxUI.closePopup({ popup: docPopup, backdrop: modalBackdrop });
}

function currentExpiryDate() {
    const value = boxExpiryMeta?.dataset.expiresAt || "";
    if (!value) return null;
    const date = new Date(value);
    return Number.isNaN(date.getTime()) ? null : date;
}

function formatDuration(ms) {
    if (ms <= 0) return "expired";
    const totalSeconds = Math.ceil(ms / 1000);
    const days = Math.floor(totalSeconds / 86400);
    const hours = Math.floor((totalSeconds % 86400) / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;
    if (days) return `${days}d ${hours}h ${minutes}m`;
    if (hours) return `${hours}h ${minutes}m ${seconds}s`;
    if (minutes) return `${minutes}m ${seconds}s`;
    return `${seconds}s`;
}

function updateExpiryCountdown() {
    if (!boxExpiryText || !boxExpiryMeta) return;
    const expiry = currentExpiryDate();
    if (!expiry) {
        boxExpiryText.textContent = "Expires after one-time download";
        return;
    }
    boxExpiryText.textContent = `Expires in ${formatDuration(expiry.getTime() - Date.now())}`;
    boxExpiryText.title = `Expires at ${expiry.toLocaleString()}`;
}

function closeContextMenu() {
    contextMenu?.classList.remove("is-visible");
    contextMenu?.setAttribute("aria-hidden", "true");
}

function showContextMenu(file, x, y) {
    if (!contextMenu) return;
    contextFile = file;
    contextMenu.style.left = `${Math.min(x, window.innerWidth - 190)}px`;
    contextMenu.style.top = `${Math.min(y, window.innerHeight - 98)}px`;
    contextMenu.classList.add("is-visible");
    contextMenu.setAttribute("aria-hidden", "false");
}

function fileData(item) {
    return {
        id: item.dataset.fileId || "",
        name: item.dataset.name || item.querySelector(".box-file-name")?.textContent || "",
        size: item.dataset.size || "",
        mime: item.dataset.mime || "",
        status: item.dataset.status || "",
        statusLabel: item.querySelector(".box-file-meta")?.textContent || "",
        downloadPath: item.dataset.downloadPath || item.getAttribute("href") || "",
        thumbnail: item.dataset.thumbnail || "",
        canDownload: item.getAttribute("aria-disabled") !== "true" && item.getAttribute("href") !== "#",
    };
}

function downloadFile(item) {
    const data = fileData(item);
    if (!data.canDownload) {
        showToast(zipOnly ? "Individual file downloads are disabled for one-time boxes. Use Download Zip." : "This file is not ready for download yet.", "warning");
        return;
    }
    window.location.href = data.downloadPath;
    setTimeout(refreshBoxStatus, 900);
}

function previewURL(data) {
    return data.canDownload ? data.downloadPath : "";
}

async function previewFile(item) {
    const data = fileData(item);
    if (zipOnly) {
        showToast("Previews are disabled for one-time boxes. Use Download Zip.", "warning");
        return;
    }
    const url = previewURL(data);
    if (!url) {
        showToast("This file is not ready to preview yet.", "warning");
        return;
    }

    const mime = data.mime.toLowerCase();
    const name = htmlEscape(data.name);
    if (mime.startsWith("image/")) {
        openPopup(`${data.name} preview`, `<img class="preview-frame" src="${htmlEscape(url)}" alt="${name}">`, { preview: true });
        return;
    }
    if (mime.startsWith("video/")) {
        openPopup(`${data.name} preview`, `<video class="preview-frame" src="${htmlEscape(url)}" controls></video>`, { preview: true });
        return;
    }
    if (mime.startsWith("audio/")) {
        openPopup(`${data.name} preview`, `<audio class="preview-frame" src="${htmlEscape(url)}" controls></audio>`, { preview: true });
        return;
    }
    if (mime === "application/pdf") {
        openPopup(`${data.name} preview`, `<iframe class="preview-frame" src="${htmlEscape(url)}" title="${name}"></iframe>`, { preview: true });
        return;
    }
    if (mime.startsWith("text/") || /\.(txt|md|json|csv|log|html|css|js)$/i.test(data.name)) {
        try {
            const response = await fetch(url);
            if (!response.ok) throw new Error("Preview failed");
            const text = await response.text();
            openPopup(`${data.name} preview`, `<pre class="code-block preview-frame is-text"><code>${htmlEscape(text.slice(0, 120000))}</code></pre>`, { preview: true });
        } catch (_) {
            showToast("The browser could not load a text preview.", "error");
        }
        return;
    }
    showToast("This file type cannot be previewed in the browser.", "warning");
}

function showProperties(item) {
    const data = fileData(item);
    const url = data.downloadPath ? new URL(data.downloadPath, window.location.origin).toString() : "Not ready";
    openPopup(`${data.name} Properties`, `
        <h3>${htmlEscape(data.name)}</h3>
        <dl class="properties-grid">
            <dt>Name</dt><dd>${htmlEscape(data.name)}</dd>
            <dt>Size</dt><dd>${htmlEscape(data.size || "Unknown")}</dd>
            <dt>Type</dt><dd>${htmlEscape(data.mime || "Unknown")}</dd>
            <dt>Status</dt><dd>${htmlEscape(data.statusLabel || data.status || "Unknown")}</dd>
            <dt>File ID</dt><dd>${htmlEscape(data.id)}</dd>
            <dt>Location</dt><dd>${htmlEscape(url)}</dd>
        </dl>
    `, { properties: true });
}

function updateBoxFile(file) {
    const item = document.querySelector(`.box-file[data-file-id="${file.id}"]`);
    if (!item) return;

    const meta = item.querySelector(".box-file-meta");
    const icon = item.querySelector(".box-file-icon");
    const isComplete = file.status === "complete";
    const isFailed = file.status === "failed";

    item.classList.toggle("is-complete", isComplete);
    item.classList.toggle("is-failed", isFailed);
    item.classList.toggle("is-loading", !isComplete && !isFailed);
    item.classList.toggle("has-thumbnail", Boolean(file.thumbnail_path));
    item.dataset.status = file.status;
    item.dataset.name = file.name || item.dataset.name || "";
    item.dataset.size = file.size_label || item.dataset.size || "";
    item.dataset.mime = file.mime_type || item.dataset.mime || "";
    item.dataset.downloadPath = file.download_path || item.dataset.downloadPath || "";
    item.dataset.thumbnail = file.thumbnail_path || "";
    item.title = file.title;

    if (isComplete && !zipOnly) {
        item.href = file.download_path;
        item.setAttribute("download", "");
        item.removeAttribute("aria-disabled");
    } else {
        item.href = "#";
        item.removeAttribute("download");
        item.setAttribute("aria-disabled", "true");
    }

    if (meta) meta.textContent = `${file.status_label} · ${file.size_label}`;
    if (icon) icon.src = file.thumbnail_path || file.icon_path;
}

async function refreshBoxStatus() {
    if (!boxPanel) return false;

    const boxID = boxPanel.dataset.boxId;
    const response = await fetch(`/box/${boxID}/status`);
    if (!response.ok) return { changed: false, hasLoadingFiles: true };

    const result = await response.json();
    const signature = statusSignature(result);
    const changed = signature !== lastStatusSignature;
    lastStatusSignature = signature;

    if (boxExpiryMeta && typeof result.expires_at === "string") {
        boxExpiryMeta.dataset.expiresAt = result.expires_at;
        updateExpiryCountdown();
    }
    result.files.forEach(updateBoxFile);

    if (boxStatus) {
        const completeCount = result.files.filter((file) => file.status === "complete").length;
        boxStatus.textContent = `${completeCount}/${result.files.length} ready`;
    }

    const hasLoadingFiles = result.files.some((file) => {
        const isUploading = file.status === "pending" || file.status === "uploading";
        const isWaitingForThumbnail = file.status === "complete" && !file.thumbnail_status && !file.thumbnail_path;
        return isUploading || isWaitingForThumbnail || file.thumbnail_status === "processing";
    });

    return { changed, hasLoadingFiles };
}

function statusSignature(result) {
    const files = Array.isArray(result.files) ? result.files : [];
    return JSON.stringify({
        expiresAt: result.expires_at || "",
        files: files.map((file) => ({
            id: file.id,
            status: file.status,
            size: file.size,
            thumbnailPath: file.thumbnail_path || "",
            thumbnailStatus: file.thumbnail_status || "",
            downloadPath: file.download_path || "",
        })),
    });
}

function pollingStages(baseMS) {
    return [
        { interval: baseMS, attempts: 10 },
        { interval: baseMS * 2, attempts: 20 },
        { interval: baseMS * 10, attempts: 100 },
    ];
}

function startStagedPolling(baseMS) {
    const stages = pollingStages(baseMS);
    let stageIndex = 0;
    let attemptsInStage = 0;
    let stopped = false;

    const tick = async () => {
        if (stopped) return;
        const stage = stages[stageIndex];
        try {
            const result = await refreshBoxStatus();
            if (result.changed) {
                stageIndex = 0;
                attemptsInStage = 0;
            } else {
                attemptsInStage += 1;
                if (attemptsInStage >= stage.attempts) {
                    stageIndex += 1;
                    attemptsInStage = 0;
                    if (stageIndex >= stages.length) {
                        stopped = true;
                        return;
                    }
                }
            }
        } catch (_) {
            attemptsInStage += 1;
        }

        if (!stopped) {
            window.setTimeout(tick, stages[stageIndex].interval);
        }
    };

    window.setTimeout(tick, stages[0].interval);
}

function runBoxAction(action) {
    const actions = {
        "fake-close": () => showToast("Close clicked. The download window is emotionally attached.", "warning"),
        minimize: () => showToast("Minimize clicked. WarpBox refuses to disappear quietly."),
        "toggle-fit": () => {
            document.body.classList.toggle("fit-window");
            showToast("Maximize clicked. The window is doing its best.");
        },
    };

    actions[action]?.();
}

function runContextAction(action, item) {
    const actions = {
        preview: () => previewFile(item),
        download: () => downloadFile(item),
        properties: () => showProperties(item),
    };

    actions[action]?.();
}

document.addEventListener("click", (event) => {
    const action = event.target.closest("[data-action]")?.dataset.action;
    if (action) runBoxAction(action);

    const contextAction = event.target.closest("[data-context-action]")?.dataset.contextAction;
    if (contextAction && contextFile) {
        event.preventDefault();
        const item = contextFile;
        closeContextMenu();
        runContextAction(contextAction, item);
        return;
    }

    if (!event.target.closest("#box-context-menu")) closeContextMenu();
});

document.querySelectorAll(".box-file").forEach((item) => {
    item.addEventListener("click", (event) => {
        if (item.getAttribute("aria-disabled") === "true") {
            event.preventDefault();
            showToast(zipOnly ? "Individual file downloads are disabled for one-time boxes. Use Download Zip." : "This file is not ready yet.", "warning");
            return;
        }
        setTimeout(refreshBoxStatus, 900);
    });
    item.addEventListener("contextmenu", (event) => {
        event.preventDefault();
        showContextMenu(item, event.clientX, event.clientY);
    });
});

boxAddress?.addEventListener("click", async () => {
    try {
        await navigator.clipboard.writeText(window.location.href);
        showToast("Current box URL copied.");
    } catch (_) {
        openPopup("Copy box URL", `<p>Clipboard access failed. Copy this URL manually.</p><textarea class="copy-fallback-text" readonly>${htmlEscape(window.location.href)}</textarea>`);
    }
});

docPopupClose?.addEventListener("click", closePopup);
modalBackdrop?.addEventListener("click", closePopup);
document.addEventListener("keydown", (event) => {
    if (event.key === "Escape") {
        closePopup();
        closeContextMenu();
    }
});

updateExpiryCountdown();
setInterval(updateExpiryCountdown, 1000);

if (boxPanel) {
    const pollMS = Number.parseInt(boxPanel.dataset.pollMs, 10) || 5000;
    startStagedPolling(pollMS);
}
