import { neoError } from "./_global--log.js";
import { extractJson } from "./_global--extract-json.js";
import { neo__ } from "./_global--translation.js";
import { getLibraryTable, addRow } from "./neo-library--globals.js";
import { updateRowAttribute } from "./neo-library--render.js";
import { animateRowShine } from "./neo-library--animations.js";
import { neoLoadInterfaceFunc } from "./_global--interface.js";
import { fetchEndpoint } from "./_global--endpoint.js";
import { jsVar } from "./_global--enqueue-loader.js";
import { observeOnce } from "./_global--observer.js";
import { isModuleAvailable } from "./_global--interface.js";



const filesToUpload = [];
async function handleFiles(files) {
    getLibraryTable().classList.remove("neo-library--dropover-animation");
    if (files.length === 0) { return; }

    const newFilesToUpload = [];
    for (const [index, file] of [...files].entries()) {
        const droppedRow = addRow();

        updateRowAttribute(droppedRow, "data-img-url",           URL.createObjectURL(file));
        updateRowAttribute(droppedRow, "data-title",             file.name.includes(".") ? file.name.slice(0, file.name.lastIndexOf(".")) : file.name);
        updateRowAttribute(droppedRow, "data-filename",          file.name);
        updateRowAttribute(droppedRow, "data-message",           `<span class="neo-library--hourglass-animation">⏳</span> ${neo__("In the queue...", "In der Warteschlange...")}`);
        updateRowAttribute(droppedRow, "data-posts-using-image", JSON.stringify([]));
        updateRowAttribute(droppedRow, "data-file-sizes",        JSON.stringify({ raw: { size: file.size } }));
        updateRowAttribute(droppedRow, "data-state",             "upload-pending");
        droppedRow.classList.add("neo-library--dropped-row-animation");
        droppedRow.style.setProperty("--neo-library--dropped-row-animation-delay", "" + (index / files.length * 1000) + "ms");
        newFilesToUpload.push({ file: file, row: droppedRow });
    }

    await new Promise(resolve => setTimeout(resolve, (files.length > 1 ? 1000 : 0) + 300));

    for (const row of newFilesToUpload.map(f => f.row)) { row.classList.remove("neo-library--dropped-row-animation"); }

    filesToUpload.push(...newFilesToUpload);
    uploadPendingFilesWorkerLoop();
}

async function uploadPendingFilesWorkerLoop() {

    const numberOfParallelWorkers = 4;
    uploadPendingFilesWorkerLoop.numberOfRunningWorkers ??= 0;
    if (uploadPendingFilesWorkerLoop.numberOfRunningWorkers >= Math.min(numberOfParallelWorkers, filesToUpload.length)) { return; }
    uploadPendingFilesWorkerLoop.numberOfRunningWorkers ++;
    for (let i=0; i<filesToUpload.length; i++) { uploadPendingFilesWorkerLoop(); }

    const getPendingFilesToUpload = () => filesToUpload.filter(f => f.row.getAttribute("data-state") === "upload-pending");
    while (getPendingFilesToUpload().length > 0) {
        const fileToUpload = getPendingFilesToUpload()[0];


        updateRowAttribute(fileToUpload.row, "data-state", "uploading"); updateRowAttribute(fileToUpload.row, "data-message", `<span class="neo-library--rocket-animation">🚀</span> ${neo__("Uploading...", "Hochladen...")}`);
        let uploadErrorMessage = null;
        let editorDialog;
        try {
            if (!(fileToUpload.file.name.toLowerCase().endsWith(".svg") || fileToUpload.file.name.toLowerCase().endsWith(".png"))) { throw new Error("neoDraw editor can only open SVG or PNG directly"); }
            if (!isModuleAvailable("neo-draw")) { throw new Error("neoDraw editor is not available"); }
            editorDialog = new (await neoLoadInterfaceFunc("neo-library", "neo-draw--editor-dialog.js", "InterfaceEditorDialog20250302"))();

            editorDialog
                .imgUrl(URL.createObjectURL(fileToUpload.file))
                .forceFilename(fileToUpload.file.name)
                .forceNew()
                .suppressInsert()
                .hidden()
                .open();

            await new Promise((resolve, reject) => {
                editorDialog.on("load", resolve);
                editorDialog.on("error", reject);
            });

            const onSavePromise = new Promise((resolve, reject) => editorDialog.on("save", resolve).on("error", reject));
            editorDialog.save();
            const { imgUrl } = await onSavePromise;

            updateRowAttribute(fileToUpload.row, "data-message", '<span class="neo-library--check-animation">✅</span> ' + neo__("Uploaded", "Hochgeladen"));
            updateRowAttribute(fileToUpload.row, "data-img-url", imgUrl);
            updateRowAttribute(fileToUpload.row, "data-is-neodraw", "true");
            updateRowAttribute(fileToUpload.row, "data-upload-date", new Date().toISOString().replace("T", " ").substring(0, 19));
            updateRowAttribute(fileToUpload.row, "data-modified-date", new Date().toISOString().replace("T", " ").substring(0, 19));
            updateRowAttribute(fileToUpload.row, "data-state", "download-pending");
            animateRowShine(fileToUpload.row);
        } catch (error) {
            uploadErrorMessage = error.message;
        } finally {
            editorDialog?.closeWithoutConfirmation();
        }

        if (uploadErrorMessage) {
            try {
                const formData = new FormData();
                formData.append("file", fileToUpload.file);
                const respText = await new Promise((resolve, reject) => {
                    let xhr = new XMLHttpRequest();
                    xhr.open("POST", jsVar("neoLibraryUploadEndpointUrl"), true);
                    xhr.setRequestHeader("X-WP-Nonce", jsVar("neoLibraryUploadEndpointNonce"));
                    xhr.setRequestHeader("X-Neo-Library", "true");
                    xhr.upload.onprogress = event => {
                        if (event.total > 0) { updateRowAttribute(fileToUpload.row, "data-message", `<span class="neo-library--rocket-animation">🚀</span> ${neo__("Uploading...", "Hochladen...")} ${Math.round(event.loaded/event.total*100)}%`); }
                        if (event.loaded >= event.total) { updateRowAttribute(fileToUpload.row, "data-message", `<span>🧬</span> ${neo__("Processing...", "Verarbeite...")}`); }
                    };
                    xhr.onload = () => {
                        if (xhr.status === 200) { resolve(xhr.responseText); }
                        else {

                            const dummyNode = document.createElement("div");
                            dummyNode.innerHTML = xhr.responseText;
                            dummyNode.querySelectorAll("style, script").forEach(node => node.remove());
                            let errorText = dummyNode.textContent;
                            try { const errorJson = extractJson(errorText); errorText = errorJson.message || errorText; } catch (err) {}
                            reject(new Error(errorText));
                        }
                    };
                    xhr.onerror = () => reject(new Error(neo__("Network error", "Netzwerkfehler")));
                    xhr.send(formData);
                });

                const imgUrl = extractJson(respText).imgUrl;

                updateRowAttribute(fileToUpload.row, "data-message", '<span class="neo-library--check-animation">✅</span> ' + neo__("Uploaded", "Hochgeladen"));
                updateRowAttribute(fileToUpload.row, "data-img-url", imgUrl);
                updateRowAttribute(fileToUpload.row, "data-is-neodraw", "false");
                updateRowAttribute(fileToUpload.row, "data-upload-date", new Date().toISOString().replace("T", " ").substring(0, 19));
                updateRowAttribute(fileToUpload.row, "data-modified-date", new Date().toISOString().replace("T", " ").substring(0, 19));
                updateRowAttribute(fileToUpload.row, "data-state", "download-pending");
                uploadErrorMessage = null;
                animateRowShine(fileToUpload.row);
            } catch (err) {
                uploadErrorMessage = err.message;
            }
        }

        if (!uploadErrorMessage) {
            const imgUrlsInOrder = filesToUpload.map(f => f.row.getAttribute("data-img-url"));
            await fetchEndpoint("/wp-json/neo/library-correct-upload-order", { method: "POST", body: { "img-urls": imgUrlsInOrder } })
                .catch(err => { neoError(err), uploadErrorMessage = neo__("Error while correcting upload order", "Fehler beim Korrigieren der Upload-Reihenfolge"); throw err; });
        }

        if (uploadErrorMessage) {
            neoError(uploadErrorMessage); updateRowAttribute(fileToUpload.row, "data-message", '<span class="cross-animation">❌</span> ' + neo__("Error", "Fehler") + ': ' + uploadErrorMessage);
        }
    }
    uploadPendingFilesWorkerLoop.numberOfRunningWorkers --;
}


observeOnce("#neo-library--file-selector", (fileSelectorNode) => fileSelectorNode.addEventListener("change", (evt) => { handleFiles(evt.target.files); evt.target.value = ""; }, false));
observeOnce("#neo-library--upload-row", (uploadRowNode) => uploadRowNode.addEventListener("click", async () => (await observeOnce("#neo-library--file-selector")).click(), false));



const canBeDropped = (evt) => evt.dataTransfer.types.includes("Files") || evt.dataTransfer.types.includes("text/html");

const dragoverHandler = (evt) => {
    evt.preventDefault();
    if (!canBeDropped(evt)) { return; }
    clearTimeout(dragoverHandler.resetDropOverClassTimeout); dragoverHandler.resetDropOverClassTimeout = setTimeout(() => getLibraryTable().classList.remove('neo-library--dropover-animation'), 400);
    if (getLibraryTable().classList.contains("neo-library--dropover-animation")) { return; }
    getLibraryTable().classList.add("neo-library--dropover-animation");
    if (window.scrollY > 0) { window.scrollTo({ top: 0, behavior: "smooth" }); }
};
(await observeOnce("body")).addEventListener("dragover", dragoverHandler, false);

(await observeOnce("body")).addEventListener("drop", (evt) => { evt.preventDefault(); if (canBeDropped(evt)) { handleFiles(evt.dataTransfer.files); } }, false);
