(() => {
  if (!window.LumiPage) return;

  window.LumiPage.register("navigation-builder", {
    selector: "[data-navigation-builder]",
    mount(root, { signal }) {
      const form = root.querySelector("#nav-form");
      const sectionList = root.querySelector("[data-section-list]");
      const unassignedList = root.querySelector("[data-unassigned-list]");
      const jsonField = root.querySelector("#nav-sections-json");
      const advancedToggle = root.querySelector("[data-advanced-toggle]");
      const advancedPanel = root.querySelector("[data-advanced-panel]");
      const status = root.querySelector("[data-nav-builder-status]");
      const dirtyBadge = root.querySelector("[data-nav-dirty-badge]");
      const saveButton = root.querySelector("button[form='nav-form']");
      if (!form || !sectionList || !unassignedList || !jsonField) return;

      const readJson = (id, fallback = []) => {
        try {
          return JSON.parse(document.getElementById(id)?.textContent || JSON.stringify(fallback));
        } catch {
          return fallback;
        }
      };

      const navItems = readJson("nav-items-data");
      const initialSections = readJson("nav-sections-data");
      const navIcons = readJson("nav-icons-data");
      const itemMap = new Map(navItems.map((item) => [item.navId, item]));
      let sectionSequence = 0;
      let canonicalSnapshot = "";
      let jsonPending = false;
      advancedPanel.hidden = true;

      const escapeHtml = (value) => String(value || "").replace(/[&<>"']/g, (char) => ({
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#39;"
      }[char]));

      const groupLists = () => [
        ...sectionList.querySelectorAll("[data-section-items]"),
        unassignedList
      ];

      const groupLabel = (list) => list.dataset.groupLabel || list.closest("[data-nav-section-card]")?.querySelector(".nav-section-label")?.value || "section";

      function buildItem(navId) {
        const data = itemMap.get(navId) || { navId, label: navId, path: navId };
        const label = String(data.label || navId);
        const item = document.createElement("article");
        item.className = "nav-dd-item";
        item.draggable = true;
        item.dataset.navId = navId;
        item.setAttribute("aria-label", `${label} navigation item`);
        item.innerHTML = `
          <span class="nav-dd-handle" aria-hidden="true">⋮⋮</span>
          <div class="nav-dd-meta">
            <strong>${escapeHtml(label)}</strong>
            <span>${escapeHtml(data.path || navId)}</span>
          </div>
          <div class="nav-item-actions" aria-label="Move ${escapeHtml(label)}">
            <button type="button" class="icon-button" data-item-up aria-label="Move ${escapeHtml(label)} up" title="Move up">↑</button>
            <button type="button" class="icon-button" data-item-down aria-label="Move ${escapeHtml(label)} down" title="Move down">↓</button>
            <button type="button" class="icon-button" data-item-previous-group aria-label="Move ${escapeHtml(label)} to the previous group" title="Move to previous group">←</button>
            <button type="button" class="icon-button" data-item-next-group aria-label="Move ${escapeHtml(label)} to the next group" title="Move to next group">→</button>
          </div>
        `;
        return item;
      }

      function buildSection(section) {
        sectionSequence += 1;
        const fieldKey = `nav-section-${sectionSequence}`;
        const card = document.createElement("section");
        card.className = "nav-section-card";
        card.dataset.navSectionCard = "";
        card.innerHTML = `
          <div class="nav-section-header">
            <div class="field">
              <label for="${fieldKey}-label">Section label</label>
              <input id="${fieldKey}-label" type="text" class="nav-section-label" value="${escapeHtml(section.label || "")}" required>
            </div>
            <div class="field">
              <label for="${fieldKey}-id">Section ID</label>
              <input id="${fieldKey}-id" type="text" class="nav-section-id" value="${escapeHtml(section.id || "")}" autocapitalize="none" spellcheck="false" required>
            </div>
            <div class="field">
              <label for="${fieldKey}-icon">Section icon</label>
              <select id="${fieldKey}-icon" class="nav-section-icon"></select>
            </div>
            <div class="nav-section-actions" aria-label="Reorder or remove section">
              <button type="button" class="icon-button" data-section-up aria-label="Move section up" title="Move section up">↑</button>
              <button type="button" class="icon-button" data-section-down aria-label="Move section down" title="Move section down">↓</button>
              <button type="button" class="button subtle" data-section-remove>Remove</button>
            </div>
          </div>
          <div class="nav-dd-list" data-section-items data-group-label="${escapeHtml(section.label || section.id || "Section")}"></div>
        `;
        const select = card.querySelector(".nav-section-icon");
        const empty = document.createElement("option");
        empty.value = "";
        empty.textContent = "No icon";
        select.append(empty);
        navIcons.forEach((icon) => {
          const option = document.createElement("option");
          option.value = icon;
          option.textContent = icon;
          option.selected = icon === String(section.icon || "").toLowerCase();
          select.append(option);
        });
        const list = card.querySelector("[data-section-items]");
        (section.items || []).forEach((navId) => {
          if (itemMap.has(navId)) list.append(buildItem(navId));
        });
        return card;
      }

      function collectSections() {
        return Array.from(sectionList.querySelectorAll("[data-nav-section-card]")).map((card, index) => {
          const label = card.querySelector(".nav-section-label").value.trim();
          const typedId = card.querySelector(".nav-section-id").value.trim();
          const id = typedId || label || `section-${index + 1}`;
          return {
            id,
            label: label || id,
            icon: card.querySelector(".nav-section-icon").value.trim(),
            items: Array.from(card.querySelectorAll(".nav-dd-item")).map((item) => item.dataset.navId)
          };
        });
      }

      function syncJson() {
        jsonPending = false;
        jsonField.dataset.pending = "false";
        jsonField.value = JSON.stringify(collectSections(), null, 2);
        if (saveButton) saveButton.disabled = false;
      }

      function snapshot() {
        const data = new FormData(form);
        return JSON.stringify(Array.from(data.entries()).map(([name, value]) => [name, String(value)]));
      }

      function updateDirtyState(message = "Navigation has unsaved changes.") {
        const dirty = snapshot() !== canonicalSnapshot;
        root.dataset.dirty = String(dirty);
        dirtyBadge.hidden = !dirty;
        if (dirty && status && !jsonPending) status.textContent = message;
        if (!dirty && status) status.textContent = "All changes are saved.";
      }

      function rebuildFromSections(sections, { focusFirst = false } = {}) {
        sectionList.replaceChildren();
        unassignedList.replaceChildren();
        const assigned = new Set();
        (sections || []).forEach((section) => {
          sectionList.append(buildSection(section));
          (section.items || []).forEach((navId) => assigned.add(navId));
        });
        navItems.forEach((item) => {
          if (!assigned.has(item.navId)) unassignedList.append(buildItem(item.navId));
        });
        syncJson();
        if (focusFirst) sectionList.querySelector(".nav-section-label")?.focus();
      }

      function applyStructureSettings(structure = {}) {
        const enabled = form.elements.namedItem("nav_enabled");
        const includeUnassigned = form.elements.namedItem("nav_include_unassigned");
        if (enabled) enabled.checked = Boolean(structure.enabled);
        if (includeUnassigned) includeUnassigned.checked = structure.includeUnassigned !== false;
        form.elements.namedItem("nav_unassigned_label").value = structure.unassignedLabel || "Other";
        form.elements.namedItem("nav_unassigned_id").value = structure.unassignedId || "other";
        form.elements.namedItem("nav_unassigned_icon").value = structure.unassignedIcon || "";
        root.querySelectorAll("[data-switch-state]").forEach((state) => {
          const input = state.closest("label")?.querySelector("input[type='checkbox']");
          state.textContent = input?.checked ? "Enabled" : "Disabled";
        });
      }

      function announce(message, role = "status") {
        if (!status) return;
        status.setAttribute("role", role);
        status.textContent = message;
      }

      function moveItem(item, direction) {
        if (!item) return;
        const sibling = direction < 0 ? item.previousElementSibling : item.nextElementSibling;
        if (!sibling) return;
        if (direction < 0) item.parentElement.insertBefore(item, sibling);
        else item.parentElement.insertBefore(sibling, item);
        syncJson();
        updateDirtyState(`${item.querySelector("strong")?.textContent || "Item"} reordered.`);
      }

      function moveItemGroup(item, direction) {
        if (!item) return;
        const lists = groupLists();
        const current = lists.indexOf(item.parentElement);
        const target = lists[current + direction];
        if (!target) return;
        target.append(item);
        syncJson();
        updateDirtyState(`${item.querySelector("strong")?.textContent || "Item"} moved to ${groupLabel(target)}.`);
      }

      function moveSection(card, direction) {
        if (!card) return;
        const sibling = direction < 0 ? card.previousElementSibling : card.nextElementSibling;
        if (!sibling) return;
        if (direction < 0) sectionList.insertBefore(card, sibling);
        else sectionList.insertBefore(sibling, card);
        syncJson();
        updateDirtyState("Section order changed.");
      }

      root.addEventListener("click", (event) => {
        const button = event.target.closest("button");
        if (!button || !root.contains(button)) return;
        const item = button.closest(".nav-dd-item");
        const card = button.closest("[data-nav-section-card]");
        if (button.matches("[data-add-section]")) {
          const existingIds = new Set(Array.from(sectionList.querySelectorAll(".nav-section-id"), (input) => input.value.trim().toLowerCase()));
          let index = sectionList.children.length + 1;
          while (existingIds.has(`section-${index}`)) index += 1;
          const next = buildSection({ id: `section-${index}`, label: `Section ${index}`, icon: "", items: [] });
          sectionList.append(next);
          syncJson();
          updateDirtyState("Section added.");
          next.querySelector(".nav-section-label")?.focus();
        } else if (button.matches("[data-advanced-toggle]")) {
          const expanded = button.getAttribute("aria-expanded") === "true";
          button.setAttribute("aria-expanded", String(!expanded));
          advancedPanel.hidden = expanded;
          if (!expanded) jsonField.focus();
        } else if (button.matches("[data-apply-json]")) {
          try {
            const parsed = JSON.parse(jsonField.value || "[]");
            if (!Array.isArray(parsed)) throw new TypeError("JSON must be an array of sections.");
            rebuildFromSections(parsed, { focusFirst: true });
            updateDirtyState("Advanced JSON applied to the visual builder.");
            announce("Advanced JSON applied. Review the visual builder, then save navigation.");
          } catch (error) {
            jsonPending = true;
            jsonField.dataset.pending = "true";
            jsonField.setAttribute("aria-invalid", "true");
            announce(error.message || "JSON is invalid.", "alert");
            jsonField.focus();
          }
        } else if (button.matches("[data-section-remove]")) {
          card.querySelectorAll(".nav-dd-item").forEach((entry) => unassignedList.append(entry));
          card.remove();
          syncJson();
          updateDirtyState("Section removed. Its items are now unassigned.");
          root.querySelector("[data-add-section]")?.focus();
        } else if (button.matches("[data-section-up]")) moveSection(card, -1);
        else if (button.matches("[data-section-down]")) moveSection(card, 1);
        else if (button.matches("[data-item-up]")) moveItem(item, -1);
        else if (button.matches("[data-item-down]")) moveItem(item, 1);
        else if (button.matches("[data-item-previous-group]")) moveItemGroup(item, -1);
        else if (button.matches("[data-item-next-group]")) moveItemGroup(item, 1);
      }, { signal });

      root.addEventListener("input", (event) => {
        if (event.target === jsonField) {
          jsonPending = true;
          jsonField.dataset.pending = "true";
          jsonField.removeAttribute("aria-invalid");
          if (saveButton) saveButton.disabled = true;
          announce("Apply the advanced JSON to the visual builder before saving.");
          root.dataset.dirty = "true";
          dirtyBadge.hidden = false;
          return;
        }
        const card = event.target.closest("[data-nav-section-card]");
        if (card && event.target.matches(".nav-section-label")) {
          card.querySelector("[data-section-items]").dataset.groupLabel = event.target.value.trim() || "Section";
        }
        root.querySelectorAll("[data-switch-state]").forEach((state) => {
          const input = state.closest("label")?.querySelector("input[type='checkbox']");
          state.textContent = input?.checked ? "Enabled" : "Disabled";
        });
        syncJson();
        updateDirtyState();
      }, { signal });

      root.addEventListener("change", (event) => {
        if (event.target === jsonField) return;
        syncJson();
        updateDirtyState();
      }, { signal });

      root.addEventListener("dragstart", (event) => {
        const item = event.target.closest(".nav-dd-item");
        if (!item) return;
        item.classList.add("dragging");
        event.dataTransfer.effectAllowed = "move";
        event.dataTransfer.setData("text/plain", item.dataset.navId || "");
      }, { signal });

      root.addEventListener("dragend", (event) => {
        const item = event.target.closest(".nav-dd-item");
        item?.classList.remove("dragging");
        root.querySelectorAll(".drag-over").forEach((entry) => entry.classList.remove("drag-over"));
        syncJson();
        updateDirtyState("Navigation item moved.");
      }, { signal });

      root.addEventListener("dragover", (event) => {
        const list = event.target.closest(".nav-dd-list");
        const dragging = root.querySelector(".nav-dd-item.dragging");
        if (!list || !dragging) return;
        event.preventDefault();
        list.classList.add("drag-over");
        const siblings = Array.from(list.querySelectorAll(".nav-dd-item:not(.dragging)"));
        const after = siblings.reduce((closest, child) => {
          const box = child.getBoundingClientRect();
          const offset = event.clientY - box.top - box.height / 2;
          return offset < 0 && offset > closest.offset ? { offset, element: child } : closest;
        }, { offset: Number.NEGATIVE_INFINITY, element: null }).element;
        if (after) list.insertBefore(dragging, after);
        else list.append(dragging);
      }, { signal });

      root.addEventListener("dragleave", (event) => {
        const list = event.target.closest(".nav-dd-list");
        if (list && !list.contains(event.relatedTarget)) list.classList.remove("drag-over");
      }, { signal });

      root.addEventListener("drop", (event) => {
        const list = event.target.closest(".nav-dd-list");
        if (!list) return;
        event.preventDefault();
        list.classList.remove("drag-over");
        syncJson();
        updateDirtyState(`Item moved to ${groupLabel(list)}.`);
      }, { signal });

      form.addEventListener("submit", () => {
        if (!jsonPending) syncJson();
      }, { signal });

      root.addEventListener("lumi:form-saved", (event) => {
        const action = event.target?.getAttribute?.("action") || "";
        if (action.endsWith("/reset")) {
          const structure = event.detail?.data?.navStructure;
          if (structure) {
            applyStructureSettings(structure);
            rebuildFromSections(structure.sections || []);
          }
          canonicalSnapshot = snapshot();
          updateDirtyState();
          announce(event.detail?.message || "Navigation reset to Lumi defaults.");
          root.querySelector("[data-add-section]")?.focus({ preventScroll: true });
          return;
        }
        if (event.target === form) {
          canonicalSnapshot = snapshot();
          updateDirtyState();
          announce(event.detail?.message || "Navigation saved.");
        }
      }, { signal });

      window.addEventListener("beforeunload", (event) => {
        if (root.dataset.dirty !== "true") return;
        event.preventDefault();
        event.returnValue = "";
      }, { signal });

      rebuildFromSections(initialSections);
      canonicalSnapshot = snapshot();
      updateDirtyState();
    }
  });
})();
