(function () {
  const realtimeCallbacks = {
    notification: [],
  };

  window.__cairnquireRealtime = {
    on: function (event, cb) {
      if (realtimeCallbacks[event]) {
        realtimeCallbacks[event].push(cb);
      }
    },
    off: function (event, cb) {
      if (realtimeCallbacks[event]) {
        realtimeCallbacks[event] = realtimeCallbacks[event].filter(function (c) {
          return c !== cb;
        });
      }
    },
  };

  const notice = document.querySelector("[data-version-notice]");
  const reload = document.querySelector("[data-version-reload]");
  const offlineNotice = document.querySelector("[data-offline-notice]");
  const cachedNotice = document.querySelector("[data-cached-notice]");
  const documentShell = document.querySelector("[data-document-path][data-document-hash]");
  const browser = document.querySelector(".miller-browser");
  const isEditing = Boolean(document.querySelector("[data-editor-form]"));

  // Auto-scroll miller browser to show the rightmost (active) column
  function scrollBrowserToRight() {
    if (!browser) return;
    requestAnimationFrame(function () {
      // Only scroll if the rightmost column is not already visible
      var tolerance = 50;
      var maxScroll = browser.scrollWidth - browser.clientWidth;
      if (maxScroll <= 0) return; // everything fits, no scroll needed
      if (browser.scrollLeft >= maxScroll - tolerance) return; // already at right edge
      browser.scrollTo({
        left: browser.scrollWidth,
        behavior: "smooth",
      });
    });
  }

  scrollBrowserToRight();

  function initColumnPreviewExpansion() {
    if (!browser) {
      return;
    }

    let hoverTimer = null;
    let expandedColumn = null;

    function isCompressedColumn(column) {
      return (
        column &&
        column.matches(".miller-column:not(:first-child):not(:last-child)")
      );
    }

    function collapseColumn(column) {
      if (!column) return;
      column.classList.remove("is-preview-expanded");
      column.style.removeProperty("--expanded-column-width");
      if (expandedColumn === column) {
        expandedColumn = null;
      }
    }

    function expandColumn(column) {
      if (!isCompressedColumn(column)) return;
      if (expandedColumn && expandedColumn !== column) {
        collapseColumn(expandedColumn);
      }

      const expandedWidth = Math.min(Math.max(column.scrollWidth + 12, 192), 384);
      column.style.setProperty("--expanded-column-width", expandedWidth + "px");
      column.classList.add("is-preview-expanded");
      expandedColumn = column;

      requestAnimationFrame(function () {
        const leftEdge = column.offsetLeft;
        const rightEdge = leftEdge + expandedWidth;
        let targetLeft = browser.scrollLeft;

        if (leftEdge < browser.scrollLeft) {
          targetLeft = leftEdge - 8;
        } else if (rightEdge > browser.scrollLeft + browser.clientWidth) {
          targetLeft = rightEdge - browser.clientWidth + 8;
        }

        browser.scrollTo({
          left: Math.max(0, targetLeft),
          behavior: "smooth",
        });
      });
    }

    function scheduleExpansion(column) {
      if (!isCompressedColumn(column)) return;
      clearTimeout(hoverTimer);
      hoverTimer = setTimeout(function () {
        expandColumn(column);
      }, 1000);
    }

    browser.querySelectorAll(".miller-column").forEach(function (column) {
      column.addEventListener("pointerenter", function () {
        scheduleExpansion(column);
      });

      column.addEventListener("mouseenter", function () {
        scheduleExpansion(column);
      });

      column.addEventListener("mouseover", function () {
        if (!isCompressedColumn(column)) return;
        if (expandedColumn === column) return;
        scheduleExpansion(column);
      });

      column.addEventListener("pointerleave", function () {
        clearTimeout(hoverTimer);
        collapseColumn(column);
      });

      column.addEventListener("mouseleave", function () {
        clearTimeout(hoverTimer);
        collapseColumn(column);
      });
    });
  }

  initColumnPreviewExpansion();

  function updateCachedUI(isCached) {
    if (!cachedNotice) return;
    cachedNotice.hidden = !isCached;
  }

  function cacheCurrentPage() {
    if (!window.MDHubCache) return;

    const html = document.documentElement.outerHTML;
    const title = document.title;
    const pagePath = window.MDHubCache.normalizePath(window.location.pathname + window.location.search);
    window.MDHubCache.cachePage(pagePath, html, title).catch(function () {});
  }

  function registerServiceWorker() {
    if (!("serviceWorker" in navigator)) return;
    window.addEventListener("load", function () {
      navigator.serviceWorker.register("/sw.js").catch(function () {});
    });
  }

  registerServiceWorker();
  updateCachedUI(Boolean(window.__MDHUB_OFFLINE_CACHED__));

  function updateOfflineUI() {
    if (!offlineNotice) return;
    if (navigator.onLine) {
      offlineNotice.hidden = true;
    } else {
      offlineNotice.hidden = false;
    }
  }

  window.addEventListener("online", function () {
    updateOfflineUI();
    fetchAndCacheDocuments();
  });

  window.addEventListener("offline", function () {
    updateOfflineUI();
    restoreBrowserFromCache();
  });

  updateOfflineUI();

  // Cache current page content
  if (documentShell && window.MDHubCache) {
    const path = documentShell.getAttribute("data-document-path");
    const title = document.title;
    const html = documentShell.querySelector(".markdown-body")?.innerHTML;
    if (path && html) {
      window.MDHubCache.cacheContent(path, html, title).catch(function () {});
    }
  }

  cacheCurrentPage();

  // Fetch and cache documents
  function fetchAndCacheDocuments() {
    if (!window.MDHubCache) return;
    fetch("/api/documents")
      .then(function (res) {
        if (!res.ok) throw new Error("fetch failed");
        return res.json();
      })
      .then(function (data) {
        if (data.documents) {
          window.MDHubCache.cacheDocuments(data.documents).catch(function () {});
        }
      })
      .catch(function () {});
  }

  fetchAndCacheDocuments();

  // Restore browser from cache when offline
  function restoreBrowserFromCache() {
    if (!browser || !window.MDHubCache) return;
    window.MDHubCache.getCachedDocuments().then(function (docs) {
      if (!docs || docs.length === 0) return;
      // The browser is already rendered server-side; we just keep it.
      // If we wanted to rebuild it from cache, we'd need the full logic.
      // For now, the existing browser HTML is likely cached by the browser itself.
    }).catch(function () {});
  }

  // Intercept browser navigation when offline
  if (browser) {
    browser.addEventListener("click", function (event) {
      const link = event.target.closest("a");
      if (!link) return;
      if (navigator.onLine) return;

      const href = link.getAttribute("href");
      if (!href || href.startsWith("http") || href.startsWith("//")) return;

      // Try to serve from cache for document pages
      if (href.startsWith("/docs/")) {
        event.preventDefault();
        const path = href.replace("/docs/", "");
        window.MDHubCache.getCachedContent(path).then(function (cached) {
          if (cached && cached.html) {
            loadCachedDocument(path, cached.title, cached.html);
          } else {
            window.location.href = href;
          }
        }).catch(function () {
          window.location.href = href;
        });
      }
    });
  }

  function loadCachedDocument(path, title, html) {
    if (!documentShell) {
      window.location.href = "/docs/" + path;
      return;
    }

    // Update URL without reloading
    history.pushState({ cachedPath: path }, title, "/docs/" + path);
    document.title = title;

    // Update document shell
    documentShell.setAttribute("data-document-path", path);
    documentShell.setAttribute("data-document-hash", "");
    const titleEl = documentShell.querySelector(".document-meta h1");
    if (titleEl) titleEl.textContent = title;
    const pathEl = documentShell.querySelector(".meta-grid code");
    if (pathEl) pathEl.textContent = path;
    const bodyEl = documentShell.querySelector(".markdown-body");
    if (bodyEl) bodyEl.innerHTML = html;

    updateCachedUI(true);
    cacheCurrentPage();

    // Re-render math and mermaid
    if (typeof renderMath === "function") renderMath();
    if (typeof renderMermaid === "function") renderMermaid();

    // Update active state in browser
    updateBrowserActiveState(path);
  }

  function updateBrowserActiveState(activePath) {
    if (!browser) return;
    browser.querySelectorAll("a.is-active").forEach(function (el) {
      el.classList.remove("is-active");
    });
    browser.querySelectorAll("a").forEach(function (link) {
      const href = link.getAttribute("href");
      if (href === "/docs/" + activePath || href === "/?folder=" + activePath) {
        link.classList.add("is-active");
      }
    });
  }

  // WebSocket realtime updates
  if (!window.WebSocket) {
    return;
  }

  const currentPath = documentShell ? documentShell.getAttribute("data-document-path") : null;
  const currentHash = documentShell ? documentShell.getAttribute("data-document-hash") : null;
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
  let reconnectTimer = null;

  function connect() {
    const socket = new WebSocket(protocol + "//" + window.location.host + "/ws");

    socket.addEventListener("open", function () {
      if (reconnectTimer) {
        clearTimeout(reconnectTimer);
        reconnectTimer = null;
      }
    });

    socket.addEventListener("message", function (event) {
      let payload;
      try {
        payload = JSON.parse(event.data);
      } catch {
        return;
      }

      if (payload.type === "notification") {
        realtimeCallbacks.notification.forEach(function (cb) {
          cb(payload.data);
        });
        return;
      }

      if (payload.type !== "document_version" || !payload.data) {
        return;
      }

      const change = payload.data;

      if (isEditing && currentPath && change.path === currentPath) {
        return;
      }

      if (currentPath && change.path === currentPath && change.hash !== currentHash) {
        if (notice) notice.hidden = false;
        return;
      }

      if (browser && !documentShell) {
        if (notice) notice.hidden = false;
      }
    });

    socket.addEventListener("close", function () {
      reconnectTimer = setTimeout(connect, 3000);
    });

    socket.addEventListener("error", function () {
      socket.close();
    });
  }

  connect();

  if (reload) {
    reload.addEventListener("click", function () {
      window.location.reload();
    });
  }

  // Handle back/forward buttons for cached documents
  window.addEventListener("popstate", function (event) {
    if (event.state && event.state.cachedPath && window.MDHubCache) {
      window.MDHubCache.getCachedContent(event.state.cachedPath).then(function (cached) {
        if (cached && cached.html) {
          loadCachedDocument(event.state.cachedPath, cached.title, cached.html);
        }
      }).catch(function () {});
    }
  });

  // Add folder button handlers
  if (browser) {
    browser.querySelectorAll(".miller-column-add-folder").forEach(function (button) {
      button.addEventListener("click", function (event) {
        event.preventDefault();
        event.stopPropagation();
        var parentPath = button.getAttribute("data-folder-path");
        var folderName = window.prompt("Folder name:");
        if (!folderName || !folderName.trim()) return;
        folderName = folderName.trim().replace(/[\\/]/g, "-");
        var docPath = parentPath ? parentPath + "/" + folderName + "/index.md" : folderName + "/index.md";
        var displayPath = docPath.replace(/\.md$/, "");
        fetch("/api/documents/" + encodeURIComponent(displayPath).replace(/%2F/g, "/"), {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ content: "# " + folderName + "\n\n", baseHash: "" }),
        }).then(function (res) {
          if (res.ok) {
            return res.json().then(function (data) {
              var path = data.path || docPath;
              var urlPath = path.replace(/\.md$/, "");
              window.location.href = "/docs/" + encodeURIComponent(urlPath).replace(/%2F/g, "/");
            });
          } else {
            return res.json().then(function (data) {
              throw new Error(data.error || "Failed to create folder");
            });
          }
        }).catch(function (err) {
          window.alert(err.message);
        });
      });
    });

    browser.querySelectorAll(".miller-column-new-file").forEach(function (button) {
      button.addEventListener("click", function (event) {
        event.preventDefault();
        event.stopPropagation();
        var parentPath = button.getAttribute("data-folder-path");
        var fileName = window.prompt("File name:");
        if (!fileName || !fileName.trim()) return;
        fileName = fileName.trim().replace(/[\\/]/g, "-");
        if (!fileName.endsWith(".md")) fileName += ".md";
        var docPath = parentPath ? parentPath + "/" + fileName : fileName;
        var displayPath = docPath.replace(/\.md$/, "");
        fetch("/api/documents/" + encodeURIComponent(displayPath).replace(/%2F/g, "/"), {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ content: "# " + fileName.replace(/\.md$/, "") + "\n\n", baseHash: "" }),
        }).then(function (res) {
          if (res.ok) {
            return res.json().then(function (data) {
              var path = data.path || docPath;
              var urlPath = path.replace(/\.md$/, "");
              window.location.href = "/docs/" + encodeURIComponent(urlPath).replace(/%2F/g, "/");
            });
          } else {
            return res.json().then(function (data) {
              throw new Error(data.error || "Failed to create file");
            });
          }
        }).catch(function (err) {
          window.alert(err.message);
        });
      });
    });
  }
})();
