(function assistantPanelsModule(globalObject, factory) {
  const api = factory(globalObject);
  if (typeof module !== "undefined" && module.exports) {
    module.exports = api;
  }
  if (globalObject?.document) {
    globalObject.LumiAssistantPanels = api.createAssistantPanelManager();
    globalObject.LumiAssistantPanels.start();
  }
})(typeof window !== "undefined" ? window : globalThis, (globalObject) => {
  function createAssistantPanelManager(options = {}) {
    const documentObject = options.document || globalObject.document;
    const fetchObject = options.fetch || globalObject.fetch?.bind(globalObject);
    const setIntervalObject = options.setInterval || globalObject.setInterval?.bind(globalObject);
    const clearIntervalObject = options.clearInterval || globalObject.clearInterval?.bind(globalObject);
    const endpoint = options.endpoint || "/api/assistant-panels";
    const diagnosticsEndpoint = options.diagnosticsEndpoint || "/api/lumi-ai/assistant/visibility-debug";
    const pollInterval = options.pollInterval || 12000;
    const lifecycles = new Map();
    const mounted = new Map();
    const loadedAssets = new Map();
    let pollTimer = null;
    let requestController = null;
    let refreshSequence = 0;
    let started = false;
    let lastPanelHtmlReturned = false;
    let lastMountSuccessful = false;
    let lastMountError = null;
    let lastEndpointStatus = null;
    let lastHtmlLength = 0;
    let lastHtmlError = null;

    function slot() {
      return documentObject?.querySelector?.("[data-assistant-panel-slot]") || null;
    }

    function syncMountedClass() {
      documentObject?.body?.classList.toggle("has-assistant-panel", mounted.has("lumi_ai"));
    }

    function register(id, lifecycle) {
      if (!id || !lifecycle) return;
      lifecycles.set(id, lifecycle);
      const current = mounted.get(id);
      if (current) mountLifecycle(id, current.root);
    }

    function mountLifecycle(id, root) {
      const lifecycle = lifecycles.get(id);
      if (!lifecycle || root.dataset.assistantPanelMounted === "true") return;
      lifecycle.mount?.(root);
      root.dataset.assistantPanelMounted = "true";
      lastMountSuccessful = true;
      reportDiagnostics();
    }

    function unmount(id) {
      const current = mounted.get(id);
      if (!current) return;
      try {
        lifecycles.get(id)?.unmount?.(current.root);
      } finally {
        current.root.remove();
        mounted.delete(id);
        syncMountedClass();
      }
    }

    async function loadAsset(type, url, version) {
      if (!url || !documentObject?.head) return;
      const key = `${type}:${url}:${version || ""}`;
      if (loadedAssets.has(key)) return loadedAssets.get(key);
      const promise = new Promise((resolve, reject) => {
        const element = documentObject.createElement(type === "style" ? "link" : "script");
        const separator = url.includes("?") ? "&" : "?";
        const source = version ? `${url}${separator}v=${encodeURIComponent(version)}` : url;
        if (type === "style") {
          element.rel = "stylesheet";
          element.href = source;
        } else {
          element.src = source;
          element.async = true;
        }
        element.onload = resolve;
        element.onerror = () => reject(new Error(`Unable to load assistant ${type}.`));
        documentObject.head.appendChild(element);
      });
      loadedAssets.set(key, promise);
      promise.catch(() => loadedAssets.delete(key));
      return promise;
    }

    function createRoot(panel) {
      if (typeof panel.html !== "string" || !panel.html.trim()) {
        throw new Error(`Assistant panel ${panel.panel_id} returned empty HTML.`);
      }
      const template = documentObject.createElement("template");
      template.innerHTML = panel.html.trim();
      const root = template.content.firstElementChild;
      if (!root) throw new Error(`Assistant panel ${panel.panel_id} returned empty HTML.`);
      if (root.dataset.assistantPanelId && root.dataset.assistantPanelId !== panel.panel_id) {
        throw new Error(`Assistant panel ${panel.panel_id} returned a mismatched panel marker.`);
      }
      root.dataset.assistantPanelId = panel.panel_id;
      root.dataset.assistantPanelVersion = panel.version || "";
      lastPanelHtmlReturned = true;
      return root;
    }

    async function mount(panel, expectedSequence = refreshSequence) {
      const target = slot();
      if (!target) throw new Error("Assistant panel slot was not found.");
      const current = mounted.get(panel.panel_id);
      const version = panel.version || "";
      if (current?.version === version) return;
      if (current) unmount(panel.panel_id);

      try {
        await loadAsset("style", panel.stylesheet, version);
        if (expectedSequence !== refreshSequence) return;
        const root = createRoot(panel);
        target.appendChild(root);
        mounted.set(panel.panel_id, { root, version });
        syncMountedClass();
        await loadAsset("script", panel.script, version);
        if (expectedSequence !== refreshSequence || mounted.get(panel.panel_id)?.root !== root) return;
        mountLifecycle(panel.panel_id, root);
        lastMountError = null;
      } catch (error) {
        lastMountSuccessful = false;
        lastMountError = error?.message || String(error);
        unmount(panel.panel_id);
      }
      await reportDiagnostics(panel.debug);
    }

    async function reconcile(payload, expectedSequence = refreshSequence) {
      if (expectedSequence !== refreshSequence) return;
      const panels = Array.isArray(payload?.panels) ? payload.panels : [];
      lastPanelHtmlReturned = panels.some((panel) => panel?.panel_id === "lumi_ai" && Boolean(panel.html));
      const lumiPanel = panels.find((panel) => panel?.panel_id === "lumi_ai");
      lastHtmlLength = typeof lumiPanel?.html === "string" ? lumiPanel.html.length : 0;
      lastHtmlError = lumiPanel?.available === false
        ? lumiPanel.reason_code || null
        : lumiPanel?.available && !lastHtmlLength
          ? "Panel endpoint returned available=true with empty HTML."
          : null;
      const availableIds = new Set(
        panels.filter((panel) => panel?.available).map((panel) => panel.panel_id)
      );
      for (const id of [...mounted.keys()]) {
        if (!availableIds.has(id)) unmount(id);
      }
      for (const panel of panels) {
        if (expectedSequence !== refreshSequence) return;
        if (panel?.available && panel.panel_id) {
          await mount(panel, expectedSequence);
        }
      }
      await reportDiagnostics(panels.find((panel) => panel?.panel_id === "lumi_ai")?.debug);
      syncMountedClass();
    }

    async function reportDiagnostics(debug) {
      if (!fetchObject) return;
      const payload = {
        assistant_slot_found: Boolean(slot()),
        frontend_loader_loaded: true,
        panel_html_returned: lastPanelHtmlReturned,
        mount_successful: lastMountSuccessful && mounted.has("lumi_ai"),
        panel_endpoint_status: lastEndpointStatus,
        panel_html_length: lastHtmlLength,
        panel_html_error: lastHtmlError,
        mount_error: lastMountError
      };
      try {
        await fetchObject(diagnosticsEndpoint, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
          cache: "no-store"
        });
        if (debug?.enabled && globalObject.console?.debug) {
          globalObject.console.debug("[Lumi Assistant visibility]", payload);
        }
      } catch {}
    }

    async function refresh() {
      if (!slot() || !fetchObject) return;
      const sequence = ++refreshSequence;
      requestController?.abort();
      requestController = typeof AbortController !== "undefined" ? new AbortController() : null;
      try {
        const response = await fetchObject(endpoint, {
          cache: "no-store",
          signal: requestController?.signal
        });
        lastEndpointStatus = response.status;
        if (!response.ok) {
          if (sequence === refreshSequence && (response.status === 401 || response.status === 403)) {
            await reconcile({ panels: [] }, sequence);
          }
          return;
        }
        const payload = await response.json();
        if (sequence === refreshSequence) await reconcile(payload, sequence);
      } catch (error) {
        if (sequence === refreshSequence && error?.name !== "AbortError") {
          await reconcile({ panels: [] }, sequence);
        }
      }
    }

    function onVisibilityChange() {
      if (!documentObject.hidden) refresh();
    }

    function start() {
      if (started) return;
      started = true;
      reportDiagnostics();
      refresh();
      pollTimer = setIntervalObject?.(refresh, pollInterval);
      globalObject.addEventListener?.("focus", refresh);
      documentObject.addEventListener?.("visibilitychange", onVisibilityChange);
    }

    function destroy() {
      requestController?.abort();
      refreshSequence += 1;
      if (pollTimer) clearIntervalObject?.(pollTimer);
      globalObject.removeEventListener?.("focus", refresh);
      documentObject?.removeEventListener?.("visibilitychange", onVisibilityChange);
      for (const id of [...mounted.keys()]) unmount(id);
      started = false;
      pollTimer = null;
    }

    return { register, refresh, reconcile, unmount, start, destroy, mounted, reportDiagnostics };
  }

  return { createAssistantPanelManager };
});
