(() => {
    "use strict";

    const editor = document.getElementById("flashcardsEditor");

    if (!editor) {
        return;
    }

    const setId = Number(editor.dataset.setId || 0);

    const elements = {
        setTitle: document.getElementById("setTitle"),
        setDescription: document.getElementById("setDescription"),
        saveStatus: document.getElementById("saveStatus"),
        summaryLibraryCount: document.getElementById("summaryLibraryCount"),
        summarySelectedCount: document.getElementById("summarySelectedCount"),
        summarySaveStatus: document.getElementById("summarySaveStatus"),

        wordSearch: document.getElementById("wordSearch"),
        topicFilter: document.getElementById("topicFilter"),
        levelFilter: document.getElementById("levelFilter"),
        filterStatus: document.getElementById("filterStatus"),
        wordLibrary: document.getElementById("wordLibrary"),
        libraryCount: document.getElementById("libraryCount"),

        selectedWords: document.getElementById("selectedWords"),
        selectedCount: document.getElementById("selectedCount"),
        selectedEmpty: document.getElementById("selectedEmpty"),

        previewCard: document.getElementById("previewCard"),
        previewImage: document.getElementById("previewImage"),
        previewWord: document.getElementById("previewWord"),
        previewIpa: document.getElementById("previewIpa"),
        previewMeaning: document.getElementById("previewMeaning"),
        previewMeta: document.getElementById("previewMeta"),
        previewExampleWrap: document.getElementById("previewExampleWrap"),
        previewExample: document.getElementById("previewExample"),
        speakButton: document.getElementById("speakButton")
    };

    let currentPreviewWord = null;
    let currentAudio = null;
    let searchTimer = null;
    let saveTimer = null;
    let draggedItem = null;

    function escapeHtml(value) {
        return String(value ?? "")
            .replaceAll("&", "&amp;")
            .replaceAll("<", "&lt;")
            .replaceAll(">", "&gt;")
            .replaceAll('"', "&quot;")
            .replaceAll("'", "&#039;");
    }

    function parseWordData(element) {
        if (!element) {
            return null;
        }

        const rawData = element.dataset.wordJson;

        if (!rawData) {
            return null;
        }

        try {
            const word = JSON.parse(rawData);

            return {
                id: Number(word.id || 0),
                word: String(word.word || ""),
                meaning: String(word.meaning || ""),
                ipa: String(word.ipa || ""),
                image: String(word.image || ""),
                audio: String(word.audio || ""),
                partOfSpeech: String(word.partOfSpeech || ""),
                level: String(word.level || ""),
                example: String(word.example || ""),
                topics: String(word.topics || "")
            };
        } catch (error) {
            console.error("Invalid word JSON:", error);
            return null;
        }
    }

    function setText(element, value) {
        if (element) {
            element.textContent = value ?? "";
        }
    }

    function setHidden(element, hidden) {
        if (element) {
            element.hidden = Boolean(hidden);
        }
    }

    function updateCountDisplays() {
        const libraryItems = elements.wordLibrary
            ? Array.from(
                elements.wordLibrary.querySelectorAll(".fc-word-item")
              ).filter((item) => !item.hidden && item.style.display !== "none").length
            : 0;

        const selectedItems = elements.selectedWords
            ? elements.selectedWords.querySelectorAll(".fc-selected-item").length
            : 0;

        setText(elements.libraryCount, libraryItems);
        setText(elements.summaryLibraryCount, libraryItems);

        setText(elements.selectedCount, selectedItems);
        setText(elements.summarySelectedCount, selectedItems);

        if (elements.selectedEmpty) {
            elements.selectedEmpty.hidden = selectedItems > 0;
        }
    }

    function setSaveState(status, message = status) {
        setText(elements.saveStatus, message);
        setText(elements.summarySaveStatus, status);

        if (elements.saveStatus) {
            elements.saveStatus.dataset.status = status.toLowerCase();
        }

        if (elements.summarySaveStatus) {
            elements.summarySaveStatus.dataset.status = status.toLowerCase();
        }
    }

    function resetPreview() {
        currentPreviewWord = null;

        if (currentAudio) {
            currentAudio.pause();
            currentAudio.currentTime = 0;
            currentAudio = null;
        }

        if (elements.previewImage) {
            elements.previewImage.innerHTML = "A";
            elements.previewImage.classList.remove("has-image");
        }

        setText(elements.previewWord, "Select a word");
        setText(
            elements.previewMeaning,
            "Click a selected word to preview it."
        );

        setText(elements.previewIpa, "");
        setHidden(elements.previewIpa, true);

        setText(elements.previewMeta, "");
        setHidden(elements.previewMeta, true);

        setText(elements.previewExample, "");
        setHidden(elements.previewExampleWrap, true);

        if (elements.speakButton) {
            elements.speakButton.disabled = true;
            elements.speakButton.dataset.audio = "";
        }
    }

    function renderPreview(word) {
        if (!word || !word.id) {
            resetPreview();
            return;
        }

        currentPreviewWord = word;

        if (currentAudio) {
            currentAudio.pause();
            currentAudio.currentTime = 0;
            currentAudio = null;
        }

        if (elements.previewImage) {
            elements.previewImage.innerHTML = "";

            if (word.image) {
                const image = document.createElement("img");

                image.src = word.image;
                image.alt = word.word;
                image.loading = "lazy";

                image.addEventListener("error", () => {
                    elements.previewImage.innerHTML =
                        escapeHtml(word.word.charAt(0).toUpperCase() || "A");

                    elements.previewImage.classList.remove("has-image");
                });

                elements.previewImage.appendChild(image);
                elements.previewImage.classList.add("has-image");
            } else {
                elements.previewImage.textContent =
                    word.word.charAt(0).toUpperCase() || "A";

                elements.previewImage.classList.remove("has-image");
            }
        }

        setText(elements.previewWord, word.word || "Unnamed word");

        if (word.ipa) {
            setText(elements.previewIpa, word.ipa);
            setHidden(elements.previewIpa, false);
        } else {
            setText(elements.previewIpa, "");
            setHidden(elements.previewIpa, true);
        }

        setText(
            elements.previewMeaning,
            word.meaning || "No Vietnamese meaning."
        );

        const metaItems = [
            word.partOfSpeech,
            word.topics,
            word.level
        ].filter(Boolean);

        if (metaItems.length > 0) {
            setText(elements.previewMeta, metaItems.join(" • "));
            setHidden(elements.previewMeta, false);
        } else {
            setText(elements.previewMeta, "");
            setHidden(elements.previewMeta, true);
        }

        if (word.example) {
            setText(elements.previewExample, word.example);
            setHidden(elements.previewExampleWrap, false);
        } else {
            setText(elements.previewExample, "");
            setHidden(elements.previewExampleWrap, true);
        }

        if (elements.speakButton) {
            elements.speakButton.disabled = !word.audio;
            elements.speakButton.dataset.audio = word.audio || "";
        }
    }

    function playCurrentAudio() {
        if (!currentPreviewWord || !currentPreviewWord.audio) {
            return;
        }

        if (currentAudio) {
            currentAudio.pause();
            currentAudio.currentTime = 0;
        }

        currentAudio = new Audio(currentPreviewWord.audio);

        if (elements.speakButton) {
            elements.speakButton.disabled = true;
            elements.speakButton.textContent = "🔊 Playing...";
        }

        currentAudio.addEventListener("ended", () => {
            if (elements.speakButton) {
                elements.speakButton.disabled = false;
                elements.speakButton.textContent = "🔊 Listen";
            }
        });

        currentAudio.addEventListener("error", () => {
            if (elements.speakButton) {
                elements.speakButton.disabled = false;
                elements.speakButton.textContent = "🔊 Listen";
            }

            window.alert("Audio file could not be played.");
        });

        currentAudio.play().catch(() => {
            if (elements.speakButton) {
                elements.speakButton.disabled = false;
                elements.speakButton.textContent = "🔊 Listen";
            }
        });
    }

    function findLibraryButton(wordId) {
        if (!elements.wordLibrary) {
            return null;
        }

        return elements.wordLibrary.querySelector(
            `[data-add-word="${Number(wordId)}"]`
        );
    }

    function markLibraryWordSelected(wordId) {
    const button = findLibraryButton(wordId);

    if (!button) {
        return;
    }

    button.disabled = false;
    button.classList.add("is-selected");
    button.dataset.selected = "1";

    const label = button.querySelector(".fc-add-label");

    if (label) {
        label.textContent = "✓ Added";
    }
}

    function markLibraryWordAvailable(wordId) {
        const button = findLibraryButton(wordId);

        if (!button) {
            return;
        }

        button.disabled = false;
        button.classList.remove("is-selected");
button.dataset.selected = "0";
        const label = button.querySelector(".fc-add-label");

        if (label) {
            label.textContent = "+ Add";
        }
    }

    function refreshOrderNumbers() {
        if (!elements.selectedWords) {
            return;
        }

        const items = elements.selectedWords.querySelectorAll(
            ".fc-selected-item"
        );

        items.forEach((item, index) => {
            const orderElement = item.querySelector(".fc-order");

            if (orderElement) {
                orderElement.textContent = String(index + 1);
            }
        });
    }

    function getSelectedWordIds() {
        if (!elements.selectedWords) {
            return [];
        }

        return Array.from(
            elements.selectedWords.querySelectorAll(".fc-selected-item")
        )
            .map((item) => Number(item.dataset.wordId || 0))
            .filter((id) => id > 0);
    }
	    async function requestJson(url, options = {}) {
        const response = await fetch(url, {
            credentials: "same-origin",
            headers: {
                "X-Requested-With": "XMLHttpRequest",
                ...(options.headers || {})
            },
            ...options
        });

        let data = null;

        try {
            data = await response.json();
        } catch (error) {
            throw new Error("Invalid server response.");
        }

        if (!response.ok || !data || data.success !== true) {
            throw new Error(
                data && data.message
                    ? data.message
                    : "The request could not be completed."
            );
        }

        return data;
    }

    function createSelectedItem(word, orderNo = 1) {
        const item = document.createElement("div");

        item.className = "fc-selected-item";
        item.draggable = true;
        item.dataset.wordId = String(word.id);
        item.dataset.wordJson = JSON.stringify(word);

        const firstLetter =
            String(word.word || "").charAt(0).toUpperCase() || "A";

        const imageHtml = word.image
            ? `<img src="${escapeHtml(word.image)}" alt="">`
            : escapeHtml(firstLetter);

        const partOfSpeechHtml = word.partOfSpeech
            ? `<em>${escapeHtml(word.partOfSpeech)}</em>`
            : "";

        item.innerHTML = `
            <span class="fc-drag" title="Drag to reorder">⋮⋮</span>
            <span class="fc-order">${Number(orderNo)}</span>
            <span class="fc-thumb fc-selected-thumb">
                ${imageHtml}
            </span>
            <span class="fc-selected-copy">
                <strong>${escapeHtml(word.word)}</strong>
                <small>${escapeHtml(word.meaning)}</small>
                ${partOfSpeechHtml}
            </span>
            <button
                type="button"
                data-remove-word="${Number(word.id)}"
                aria-label="Remove ${escapeHtml(word.word)}"
            >×</button>
        `;

        return item;
    }

    function addWordToSelectedList(word) {
        if (!elements.selectedWords || !word || !word.id) {
            return;
        }

        const existing = elements.selectedWords.querySelector(
            `[data-word-id="${Number(word.id)}"]`
        );

        if (existing) {
            renderPreview(parseWordData(existing));
            return;
        }

        const orderNo =
            elements.selectedWords.querySelectorAll(".fc-selected-item").length + 1;

        const item = createSelectedItem(word, orderNo);

        elements.selectedWords.appendChild(item);

        markLibraryWordSelected(word.id);
        refreshOrderNumbers();
        updateCountDisplays();
        renderPreview(word);
    }

    function removeWordFromSelectedList(wordId) {
        if (!elements.selectedWords) {
            return;
        }

        const item = elements.selectedWords.querySelector(
            `[data-word-id="${Number(wordId)}"]`
        );

        if (!item) {
            return;
        }

        const removedWord = parseWordData(item);

        item.remove();

        markLibraryWordAvailable(wordId);
        refreshOrderNumbers();
        updateCountDisplays();

        if (
            currentPreviewWord &&
            Number(currentPreviewWord.id) === Number(wordId)
        ) {
            const firstRemainingItem =
                elements.selectedWords.querySelector(".fc-selected-item");

            if (firstRemainingItem) {
                renderPreview(parseWordData(firstRemainingItem));
            } else {
                resetPreview();
            }
        }

        return removedWord;
    }

    async function addWord(wordId, button) {
        if (!wordId || !button || button.disabled) {
            return;
        }

        const word = parseWordData(button);

        if (!word) {
            window.alert("Word data is missing.");
            return;
        }

        button.disabled = true;

        const label = button.querySelector(".fc-add-label");

        if (label) {
            label.textContent = "Adding...";
        }

        try {
            const formData = new FormData();

            formData.append("set_id", String(setId));
            formData.append("word_id", String(wordId));

            const data = await requestJson("ajax/add_word.php", {
                method: "POST",
                body: formData
            });

            if (data.word && typeof data.word === "object") {
                const serverWord = {
                    id: Number(data.word.id || word.id),
                    word: String(data.word.word || word.word),
                    meaning: String(
                        data.word.meaning ??
                        data.word.meaning_vi ??
                        word.meaning
                    ),
                    ipa: String(
                        data.word.ipa ??
                        data.word.phonetic ??
                        word.ipa
                    ),
                    image: String(
                        data.word.image ??
                        data.word.image_path ??
                        word.image
                    ),
                    audio: String(
                        data.word.audio ??
                        data.word.audio_us_path ??
                        word.audio
                    ),
                    partOfSpeech: String(
                        data.word.partOfSpeech ??
                        data.word.part_of_speech ??
                        word.partOfSpeech
                    ),
                    level: String(
                        data.word.level ??
                        word.level
                    ),
                    example: String(
                        data.word.example ??
                        data.word.example_en ??
                        word.example
                    ),
                    topics: String(
                        data.word.topics ??
                        word.topics
                    )
                };

                addWordToSelectedList(serverWord);
            } else {
                addWordToSelectedList(word);
            }

            setSaveState("Saved", "Saved");
        } catch (error) {
            console.error(error);

            button.disabled = false;

            if (label) {
                label.textContent = "+ Add";
            }

            window.alert(error.message);
        }
    }

    async function removeWord(wordId, button) {
        if (!wordId || !button) {
            return;
        }

        const item = button.closest(".fc-selected-item");

        if (!item) {
            return;
        }

        button.disabled = true;
        setSaveState("Saving", "Saving...");

        try {
            const formData = new FormData();

            formData.append("set_id", String(setId));
            formData.append("word_id", String(wordId));

            await requestJson("ajax/remove_word.php", {
                method: "POST",
                body: formData
            });

            removeWordFromSelectedList(wordId);
            setSaveState("Saved", "Saved");
        } catch (error) {
            console.error(error);

            button.disabled = false;
            setSaveState("Error", "Save failed");

            window.alert(error.message);
        }
    }

    function normalizeLibraryWord(rawWord) {
        return {
            id: Number(rawWord.id || 0),
            word: String(rawWord.word || ""),
            meaning: String(
                rawWord.meaning ??
                rawWord.meaning_vi ??
                ""
            ),
            ipa: String(
                rawWord.ipa ??
                rawWord.phonetic ??
                ""
            ),
            image: String(
                rawWord.image ??
                rawWord.image_path ??
                ""
            ),
            audio: String(
                rawWord.audio ??
                rawWord.audio_us_path ??
                ""
            ),
            partOfSpeech: String(
                rawWord.partOfSpeech ??
                rawWord.part_of_speech ??
                ""
            ),
            level: String(
                rawWord.level ??
                (
                    rawWord.difficulty_level
                        ? `Level ${Number(rawWord.difficulty_level)}`
                        : ""
                )
            ),
            example: String(
                rawWord.example ??
                rawWord.example_en ??
                ""
            ),
            topics: String(rawWord.topics || "")
        };
    }

    function createLibraryButton(word, selectedIds) {
        const button = document.createElement("button");
        const isSelected = selectedIds.includes(Number(word.id));

        button.className =
            "fc-word-item" + (isSelected ? " is-selected" : "");

        button.type = "button";
        button.dataset.addWord = String(word.id);
        button.dataset.wordJson = JSON.stringify(word);
        button.disabled = isSelected;

        const firstLetter =
            String(word.word || "").charAt(0).toUpperCase() || "A";

        const imageHtml = word.image
            ? `<img src="${escapeHtml(word.image)}" alt="">`
            : escapeHtml(firstLetter);

        button.innerHTML = `
            <span class="fc-thumb">
                ${imageHtml}
            </span>
            <span class="fc-word-copy">
                <strong>${escapeHtml(word.word)}</strong>
                <small>${escapeHtml(word.meaning)}</small>
            </span>
            <span class="fc-add-label">
                ${isSelected ? "✓ Added" : "+ Add"}
            </span>
        `;

        return button;
    }

    function renderLibrary(words) {
        if (!elements.wordLibrary) {
            return;
        }

        const selectedIds = getSelectedWordIds();

        elements.wordLibrary.innerHTML = "";

        words.forEach((rawWord) => {
            const word = normalizeLibraryWord(rawWord);

            if (!word.id) {
                return;
            }

            elements.wordLibrary.appendChild(
                createLibraryButton(word, selectedIds)
            );
        });

        updateCountDisplays();
    }

    async function searchWords(query) {
        if (!elements.wordLibrary) return;
        elements.wordLibrary.setAttribute("aria-busy","true");
        try{
            const params=new URLSearchParams();
            params.set("set_id",String(setId));
            params.set("q",query||"");
            if(elements.topicFilter&&elements.topicFilter.value) params.set("topic",elements.topicFilter.value);
            if(elements.levelFilter&&elements.levelFilter.value) params.set("level",elements.levelFilter.value);
            const data=await requestJson(`ajax/search.php?${params.toString()}`,{method:"GET"});
            renderLibrary(Array.isArray(data.words)?data.words:[]);
        }catch(error){console.error(error);}
        finally{elements.wordLibrary.removeAttribute("aria-busy");}
    }

    function queueSearch() {
        window.clearTimeout(searchTimer);

        searchTimer = window.setTimeout(() => {
            const query = elements.wordSearch
                ? elements.wordSearch.value.trim()
                : "";

            searchWords(query);
        }, 300);
    }

    async function saveOrder() {
        const wordIds = getSelectedWordIds();

        if (wordIds.length === 0) {
            return;
        }

        setSaveState("Saving", "Saving order...");

        try {
            const formData = new FormData();

            formData.append("set_id", String(setId));

            wordIds.forEach((wordId, index) => {
                formData.append("word_ids[]", String(wordId));
                formData.append("orders[]", String(index + 1));
            });

            await requestJson("ajax/reorder.php", {
                method: "POST",
                body: formData
            });

            setSaveState("Saved", "Saved");
        } catch (error) {
            console.error(error);
            setSaveState("Error", "Order save failed");
            window.alert(error.message);
        }
    }

    function queueOrderSave() {
        window.clearTimeout(saveTimer);

        saveTimer = window.setTimeout(() => {
            saveOrder();
        }, 250);
    }

    function getDragAfterElement(container, mouseY) {
        const draggableElements = Array.from(
            container.querySelectorAll(
                ".fc-selected-item:not(.is-dragging)"
            )
        );

        return draggableElements.reduce(
            (closest, child) => {
                const box = child.getBoundingClientRect();
                const offset = mouseY - box.top - box.height / 2;

                if (
                    offset < 0 &&
                    offset > closest.offset
                ) {
                    return {
                        offset,
                        element: child
                    };
                }

                return closest;
            },
            {
                offset: Number.NEGATIVE_INFINITY,
                element: null
            }
        ).element;
    }

    function handleDragStart(event) {
        const item = event.target.closest(".fc-selected-item");

        if (!item) {
            return;
        }

        draggedItem = item;
        item.classList.add("is-dragging");

        if (event.dataTransfer) {
            event.dataTransfer.effectAllowed = "move";
            event.dataTransfer.setData(
                "text/plain",
                item.dataset.wordId || ""
            );
        }
    }

    function handleDragOver(event) {
        if (!draggedItem || !elements.selectedWords) {
            return;
        }

        event.preventDefault();

        const afterElement = getDragAfterElement(
            elements.selectedWords,
            event.clientY
        );

        if (!afterElement) {
            elements.selectedWords.appendChild(draggedItem);
        } else {
            elements.selectedWords.insertBefore(
                draggedItem,
                afterElement
            );
        }

        refreshOrderNumbers();
    }

    function handleDragEnd() {
        if (!draggedItem) {
            return;
        }

        draggedItem.classList.remove("is-dragging");
        draggedItem = null;

        refreshOrderNumbers();
        queueOrderSave();
    }
	    function handleEditorClick(event) {
        const addButton = event.target.closest("[data-add-word]");

if (addButton && elements.wordLibrary?.contains(addButton)) {
    const word = parseWordData(addButton);

    if (
        addButton.classList.contains("is-selected") ||
        addButton.dataset.selected === "1"
    ) {
        if (word) {
            renderPreview(word);
        }

        elements.wordLibrary
            .querySelectorAll(".fc-word-item.is-active")
            .forEach((item) => item.classList.remove("is-active"));

        addButton.classList.add("is-active");
        return;
    }

    const wordId = Number(addButton.dataset.addWord || 0);
    addWord(wordId, addButton);
    return;
}

        const removeButton = event.target.closest("[data-remove-word]");

        if (removeButton && elements.selectedWords?.contains(removeButton)) {
            const wordId = Number(removeButton.dataset.removeWord || 0);

            removeWord(wordId, removeButton);
            return;
        }

        const selectedItem = event.target.closest(".fc-selected-item");

        if (selectedItem && elements.selectedWords?.contains(selectedItem)) {
            const word = parseWordData(selectedItem);

            if (word) {
                renderPreview(word);
            }

            elements.selectedWords
                .querySelectorAll(".fc-selected-item.is-active")
                .forEach((item) => {
                    item.classList.remove("is-active");
                });

            selectedItem.classList.add("is-active");
            return;
        }

        const libraryItem = event.target.closest(".fc-word-item");

        if (libraryItem && elements.wordLibrary?.contains(libraryItem)) {
            const word = parseWordData(libraryItem);

            if (word) {
                renderPreview(word);
            }
        }
    }

    function handleSpeakButtonClick() {
        playCurrentAudio();
    }

    function initializePreview() {
        if (!elements.selectedWords) {
            resetPreview();
            return;
        }

        const firstSelectedItem =
            elements.selectedWords.querySelector(".fc-selected-item");

        if (!firstSelectedItem) {
            resetPreview();
            return;
        }

        const firstWord = parseWordData(firstSelectedItem);

        if (firstWord) {
            renderPreview(firstWord);
            firstSelectedItem.classList.add("is-active");
        } else {
            resetPreview();
        }
    }

    function setupDragAndDrop() {
        if (!elements.selectedWords) {
            return;
        }

        elements.selectedWords.addEventListener(
            "dragstart",
            handleDragStart
        );

        elements.selectedWords.addEventListener(
            "dragover",
            handleDragOver
        );

        elements.selectedWords.addEventListener(
            "dragend",
            handleDragEnd
        );
    }

    function normalizeFilterText(value) {
        return String(value || "")
            .toLocaleLowerCase("vi")
            .normalize("NFD")
            .replace(/[\u0300-\u036f]/g, "")
            .trim();
    }

    function applyLibraryFilters() {
        if (!elements.wordLibrary) {
            return;
        }

        const keyword = normalizeFilterText(
            elements.wordSearch ? elements.wordSearch.value : ""
        );

        const topic = normalizeFilterText(
            elements.topicFilter ? elements.topicFilter.value : ""
        );

        const level = String(
            elements.levelFilter ? elements.levelFilter.value : ""
        );

        const items = Array.from(
            elements.wordLibrary.querySelectorAll(".fc-word-item")
        );

        let visibleCount = 0;

        items.forEach((item) => {
            const word = parseWordData(item) || {};

            const searchText = normalizeFilterText(
                item.dataset.searchText || [
                    word.word,
                    word.meaning,
                    word.ipa
                ].filter(Boolean).join(" ")
            );

            const topics = normalizeFilterText(
                item.dataset.topics || word.topics || ""
            )
                .split(",")
                .map((value) => value.trim())
                .filter(Boolean);

            const itemLevel = String(
                item.dataset.levelValue ||
                item.dataset.level ||
                String(word.level || "").replace(/\D+/g, "")
            );

            const matchesSearch = keyword === ""
                || searchText.includes(keyword);

            const matchesTopic = topic === ""
                || topics.includes(topic);

            const matchesLevel = level === ""
                || itemLevel === level;

            const visible = matchesSearch && matchesTopic && matchesLevel;

            item.hidden = !visible;
            item.style.display = visible ? "" : "none";

            if (visible) {
                visibleCount += 1;
            }
        });

        setText(elements.libraryCount, visibleCount);
        setText(elements.summaryLibraryCount, visibleCount);

        if (elements.filterStatus) {
            const filtering = keyword !== "" || topic !== "" || level !== "";

            elements.filterStatus.textContent = filtering
                ? `${visibleCount} matching words`
                : `${visibleCount} words available`;
        }
    }

    function setupSearch() {
        const runFilter = () => {
            window.clearTimeout(searchTimer);
            searchTimer = window.setTimeout(applyLibraryFilters, 0);
        };

        if (elements.wordSearch) {
            elements.wordSearch.addEventListener("input", runFilter);
            elements.wordSearch.addEventListener("search", runFilter);
            elements.wordSearch.addEventListener("keydown", (event) => {
                if (event.key === "Enter") {
                    event.preventDefault();
                    applyLibraryFilters();
                }
            });
        }

        if (elements.topicFilter) {
            elements.topicFilter.addEventListener("change", runFilter);
        }

        if (elements.levelFilter) {
            elements.levelFilter.addEventListener("change", runFilter);
        }

        applyLibraryFilters();
    }

    function setupTitleAndDescriptionSaving() {
        const queueMetadataSave = () => {
            window.clearTimeout(saveTimer);

            setSaveState("Unsaved", "Unsaved changes");

            saveTimer = window.setTimeout(async () => {
                const title = elements.setTitle
                    ? elements.setTitle.value.trim()
                    : "";

                const description = elements.setDescription
                    ? elements.setDescription.value.trim()
                    : "";

                if (!title) {
                    setSaveState("Error", "Title is required");
                    return;
                }

                setSaveState("Saving", "Saving...");

                try {
                    const formData = new FormData();

                    formData.append("set_id", String(setId));
                    formData.append("title", title);
                    formData.append("description", description);

                    await requestJson("ajax/update-set.php", {
                        method: "POST",
                        body: formData
                    });

                    setSaveState("Saved", "Saved");
                } catch (error) {
                    console.error(error);
                    setSaveState("Error", "Save failed");
                }
            }, 700);
        };

        if (elements.setTitle) {
            elements.setTitle.addEventListener(
                "input",
                queueMetadataSave
            );
        }

        if (elements.setDescription) {
            elements.setDescription.addEventListener(
                "input",
                queueMetadataSave
            );
        }
    }

    function improveSummarySpacing() {
        const summary = editor.querySelector(".fc-summary");

        if (!summary) {
            return;
        }

        summary.style.display = "flex";
        summary.style.flexWrap = "wrap";
        summary.style.gap = "12px";
        summary.style.margin = "12px 0 16px";

        summary.querySelectorAll(":scope > div").forEach((item) => {
            item.style.display = "flex";
            item.style.alignItems = "center";
            item.style.gap = "8px";
            item.style.padding = "8px 12px";
            item.style.background = "#ffffff";
            item.style.border = "1px solid #e5e7eb";
            item.style.borderRadius = "10px";
        });

        summary.querySelectorAll("strong").forEach((value) => {
            value.style.fontWeight = "700";
        });
    }

    function ensureInitialLibraryStates() {
        if (!elements.wordLibrary) {
            return;
        }

        const selectedIds = getSelectedWordIds();

        elements.wordLibrary
            .querySelectorAll(".fc-word-item")
            .forEach((button) => {
                const wordId = Number(
                    button.dataset.addWord || 0
                );

                const label =
                    button.querySelector(".fc-add-label");

                if (selectedIds.includes(wordId)) {
                    button.disabled = false;
button.classList.add("is-selected");
button.dataset.selected = "1";

                    if (label) {
                        label.textContent = "✓ Added";
                    }
                } else {
                    button.disabled = false;
                    button.classList.remove("is-selected");
button.dataset.selected = "0";
                    if (label) {
                        label.textContent = "+ Add";
                    }
                }
            });
    }

    function initialize() {
        updateCountDisplays();
        ensureInitialLibraryStates();
        initializePreview();
        setupDragAndDrop();
        setupSearch();
        setupTitleAndDescriptionSaving();
        improveSummarySpacing();

        editor.addEventListener(
            "click",
            handleEditorClick
        );

        if (elements.speakButton) {
            elements.speakButton.addEventListener(
                "click",
                handleSpeakButtonClick
            );
        }
    }

    initialize();
})();
