const doc = document;
const win = window;
const windowPrefix = "w";
const documentPrefix = "d";
const events = /* @__PURE__ */ new Set();
const roots = /* @__PURE__ */ new Set([doc]);
const symbols = /* @__PURE__ */ new Map();
let observer;
let hasInitialized;
const nativeQuerySelectorAll = (root, selector) => Array.from(root.querySelectorAll(selector));
const querySelectorAll = (query) => {
  const elements = [];
  roots.forEach((root) => elements.push(...nativeQuerySelectorAll(root, query)));
  return elements;
};
const addEventListener = (el, eventName, handler, capture = false) => el.addEventListener(eventName, handler, { capture, passive: false });
const findShadowRoots = (fragment) => {
  addEventOrRoot(fragment);
  nativeQuerySelectorAll(fragment, "[q\\:shadowroot]").forEach((parent) => {
    const shadowRoot = parent.shadowRoot;
    shadowRoot && findShadowRoots(shadowRoot);
  });
};
const isPromise = (promise) => promise && typeof promise.then === "function";
const resolveContainer = (containerEl) => {
  if (containerEl._qwikjson_ === void 0) {
    const parentJSON = containerEl === doc.documentElement ? doc.body : containerEl;
    let script = parentJSON.lastElementChild;
    while (script) {
      if (script.tagName === "SCRIPT" && script.getAttribute("type") === "qwik/json") {
        containerEl._qwikjson_ = JSON.parse(
          script.textContent.replace(/\\x3C(\/?script)/gi, "<$1")
        );
        break;
      }
      script = script.previousElementSibling;
    }
  }
};
const createEvent = (eventName, detail) => new CustomEvent(eventName, { detail });
const emitEvent = (eventName, detail) => {
  doc.dispatchEvent(createEvent(eventName, detail));
};
const camelToKebab = (str) => str.replace(/([A-Z-])/g, (a) => "-" + a.toLowerCase());
const kebabToCamel = (eventName) => eventName.replace(/-./g, (a) => a[1].toUpperCase());
const parseKebabEvent = (event) => ({
  scope: event.charAt(0),
  eventName: kebabToCamel(event.slice(2))
});
const dispatch = async (element, ev, scopedKebabName, kebabName) => {
  if (kebabName) {
    if (element.hasAttribute("preventdefault:" + kebabName)) {
      ev.preventDefault();
    }
    if (element.hasAttribute("stoppropagation:" + kebabName)) {
      ev.stopPropagation();
    }
  }
  const handlers = element._qDispatch?.[scopedKebabName];
  if (handlers) {
    if (handlers.length) {
      for (const handler of handlers) {
        const result = handler?.(ev, element);
        if (isPromise(result)) {
          await result;
        }
      }
    }
    return;
  }
  const attrValue = element.getAttribute("q-" + scopedKebabName);
  if (attrValue) {
    const container = element.closest(
      "[q\\:container]:not([q\\:container=html]):not([q\\:container=text])"
    );
    const qBase = container.getAttribute("q:base");
    const base = new URL(qBase, doc.baseURI);
    for (const qrl of attrValue.split("|")) {
      const reqTime = performance.now();
      const [chunk, symbol, capturedIds] = qrl.split("#");
      const eventData = {
        qBase,
        symbol,
        element,
        reqTime
      };
      let handler;
      let importError;
      let error;
      if (chunk === "") {
        const hash = container.getAttribute("q:instance");
        handler = (doc["qFuncs_" + hash] || [])[Number.parseInt(symbol)];
        if (!handler) {
          importError = "sync";
          error = new Error("sym:" + symbol);
        }
      } else {
        const key = `${symbol}|${qBase}|${chunk}`;
        handler = symbols.get(key);
        if (!handler) {
          const href = new URL(chunk, base).href;
          try {
            const module = import(
              /* @vite-ignore */
              href
            );
            resolveContainer(container);
            handler = (await module)[symbol];
            if (!handler) {
              importError = "no-symbol";
              error = new Error(`${symbol} not in ${href}`);
            } else {
              symbols.set(key, handler);
              emitEvent("qsymbol", eventData);
            }
          } catch (err) {
            importError = "async";
            error = err;
          }
        }
      }
      if (!handler) {
        emitEvent("qerror", {
          importError,
          error,
          ...eventData
        });
        console.error(error);
        continue;
      }
      if (element.isConnected) {
        try {
          const result = handler.call(capturedIds, ev, element);
          if (isPromise(result)) {
            await result;
          }
        } catch (error2) {
          emitEvent("qerror", { error: error2, ...eventData });
        }
      }
    }
  }
};
const processElementEvent = async (ev) => {
  const kebabName = camelToKebab(ev.type);
  const scopedKebabName = "e:" + kebabName;
  let element = ev.target;
  while (element && element.getAttribute) {
    const results = dispatch(element, ev, scopedKebabName, kebabName);
    const doBubble = ev.bubbles && !ev.cancelBubble;
    if (isPromise(results)) {
      await results;
    }
    element = doBubble && ev.bubbles && !ev.cancelBubble ? element.parentElement : null;
  }
};
const broadcast = (infix, ev) => {
  const kebabName = camelToKebab(ev.type);
  const scopedKebabName = infix + ":" + kebabName;
  querySelectorAll("[q-" + infix + "\\:" + kebabName + "]").forEach(
    (el) => dispatch(el, ev, scopedKebabName, kebabName)
  );
};
const processDocumentEvent = async (ev) => {
  broadcast(documentPrefix, ev);
};
const processWindowEvent = (ev) => {
  broadcast(windowPrefix, ev);
};
const processReadyStateChange = () => {
  const readyState = doc.readyState;
  if (readyState == "interactive" || readyState == "complete") {
    hasInitialized = 1;
    roots.forEach(findShadowRoots);
    if (events.has("d:qinit")) {
      events.delete("d:qinit");
      const ev = createEvent("qinit");
      querySelectorAll("[q-d\\:qinit]").forEach((el) => {
        dispatch(el, ev, "d:qinit");
        el.removeAttribute("q-d:qinit");
      });
    }
    if (events.has("d:qidle")) {
      events.delete("d:qidle");
      const riC = win.requestIdleCallback ?? win.setTimeout;
      riC.bind(win)(() => {
        const ev = createEvent("qidle");
        querySelectorAll("[q-d\\:qidle]").forEach((el) => {
          dispatch(el, ev, "d:qidle");
          el.removeAttribute("q-d:qidle");
        });
      });
    }
    if (events.has("e:qvisible")) {
      observer || (observer = new IntersectionObserver((entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            observer.unobserve(entry.target);
            dispatch(entry.target, createEvent("qvisible", entry), "e:qvisible");
          }
        }
      }));
      querySelectorAll("[q-e\\:qvisible]:not([q\\:observed])").forEach((el) => {
        observer.observe(el);
        el.setAttribute("q:observed", "true");
      });
    }
  }
};
const addEventOrRoot = (...eventNames) => {
  for (const eventNameOrRoot of eventNames) {
    if (typeof eventNameOrRoot === "string") {
      if (!events.has(eventNameOrRoot)) {
        events.add(eventNameOrRoot);
        const { scope, eventName } = parseKebabEvent(eventNameOrRoot);
        if (scope === windowPrefix) {
          addEventListener(win, eventName, processWindowEvent, true);
        } else {
          roots.forEach(
            (root) => addEventListener(
              root,
              eventName,
              scope === documentPrefix ? processDocumentEvent : processElementEvent,
              true
            )
          );
        }
        if (hasInitialized === 1 && (eventNameOrRoot === "e:qvisible" || eventNameOrRoot === "d:qinit" || eventNameOrRoot === "d:qidle")) {
          processReadyStateChange();
        }
      }
    } else {
      if (!roots.has(eventNameOrRoot)) {
        events.forEach((kebabEventName) => {
          const { scope, eventName } = parseKebabEvent(kebabEventName);
          if (scope !== windowPrefix) {
            addEventListener(
              eventNameOrRoot,
              eventName,
              scope === documentPrefix ? processDocumentEvent : processElementEvent,
              true
            );
          }
        });
        roots.add(eventNameOrRoot);
      }
    }
  }
};
const _qwikEv = win._qwikEv;
if (!_qwikEv?.roots) {
  if (Array.isArray(_qwikEv)) {
    addEventOrRoot(..._qwikEv);
  } else {
    addEventOrRoot("e:click", "e:input");
  }
  win._qwikEv = {
    events,
    roots,
    push: addEventOrRoot
  };
  addEventListener(doc, "readystatechange", processReadyStateChange);
  processReadyStateChange();
}
