export default (() => {
  const storageSupport = "sessionStorage" in window && "BroadcastChannel" in window;
  let pagy = "pagy", storage, sync, tabId;
  if (storageSupport) {
    storage = sessionStorage;
    sync = new BroadcastChannel(pagy);
    tabId = Date.now();
    sync.addEventListener("message", (e) => {
      if (e.data.from) {
        const cutoffs = storage.getItem(e.data.key);
        if (cutoffs) {
          sync.postMessage({ to: e.data.from, key: e.data.key, str: cutoffs });
        }
      } else if (e.data.to) {
        if (e.data.to == tabId) {
          storage.setItem(e.data.key, e.data.str);
        }
      }
    });
  }
  const rjsObserver = new ResizeObserver((entries) => {
    entries.forEach((e) => {
      e.target.querySelectorAll(".series-nav-js").forEach((el) => {
        el.render();
      });
    });
  });
  const B64SafeEncode = (unicode) => btoa(String.fromCharCode(...new TextEncoder().encode(unicode))).replace(/[+/=]/g, (m) => m == "+" ? "-" : m == "/" ? "_" : ""), B64Decode = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
  const randKey = () => Math.floor(Math.random() * 36 ** 3).toString(36);
  const augmentKeynav = async (nav, [storageKey, rootKey, pageKey, last, spliceArgs]) => {
    let augmentPage;
    const browserKey = document.cookie.split(/;\s+/).find((row) => row.startsWith(pagy + "="))?.split("=")[1] ?? randKey();
    document.cookie = `${pagy}=${browserKey}`;
    if (storageKey && !(storageKey in storage)) {
      sync.postMessage({ from: tabId, key: storageKey });
      await new Promise((resolve) => setTimeout(() => {
        resolve("");
      }, 100));
      if (!(storageKey in storage)) {
        augmentPage = (page) => `${page}+${String(last)}`;
      }
    }
    if (!augmentPage) {
      if (!storageKey) {
        do {
          storageKey = randKey();
        } while (storageKey in storage);
      }
      const data = storage.getItem(storageKey), cutoffs = data ? JSON.parse(data) : [undefined];
      if (spliceArgs) {
        cutoffs.splice(...spliceArgs);
        storage.setItem(storageKey, JSON.stringify(cutoffs));
      }
      augmentPage = (page) => {
        const pageNum = parseInt(page);
        return B64SafeEncode(JSON.stringify([
          browserKey,
          storageKey,
          pageNum,
          cutoffs.length,
          cutoffs[pageNum - 1],
          cutoffs[pageNum]
        ]));
      };
    }
    const search = rootKey ? `${rootKey}%5B${pageKey}%5D` : pageKey;
    const re = new RegExp(`(?<=\\?.*)(\\b${search}=)(\\d+)`);
    for (const a of nav.querySelectorAll("a[href]")) {
      a.href = a.href.replace(re, (_match, prefix, digit) => `${String(prefix)}${augmentPage(digit)}`);
    }
    return augmentPage;
  };
  const buildNavJs = (nav, [
    [before, anchor, current, gap, after],
    pageToken,
    [widths, series, labels],
    keynavArgs
  ]) => {
    let lastWidth = -1;
    const parent = nav.parentElement;
    nav.render = () => {
      const index = widths.findIndex((w) => w < parent.clientWidth);
      if (index === -1 || widths[index] === lastWidth) {
        return;
      }
      let html = before;
      series[index].forEach((item, i) => {
        html += item == "gap" ? gap : (typeof item == "number" ? anchor.replace(pageToken, item) : current).replace("L<", labels?.[index][i] ?? `${String(item)}<`);
      });
      html += after;
      nav.innerHTML = "";
      nav.insertAdjacentHTML("afterbegin", html);
      lastWidth = widths[index];
      if (keynavArgs && storageSupport) {
        augmentKeynav(nav, keynavArgs);
      }
    };
    rjsObserver.observe(parent);
  };
  const initInputNavJs = async (nav, [url_token, pageToken, keynavArgs]) => {
    const augment = keynavArgs && storageSupport ? await augmentKeynav(nav, keynavArgs) : (page) => page;
    initInput(nav, (inputValue) => url_token.replace(pageToken, augment(inputValue)));
  };
  const initLimitTagJs = (span, [from, url_token, page_token, limitToken]) => {
    initInput(span, (inputValue) => {
      return url_token.replace(page_token, Math.max(Math.ceil(from / parseInt(inputValue)), 1)).replace(limitToken, inputValue);
    });
  };
  const initInput = (element, getUrl) => {
    const input = element.querySelector("input"), link = element.querySelector("a");
    let initial = input.value;
    const action = () => {
      if (input.value === initial) {
        return;
      }
      const [min, val, max] = [input.min, input.value, input.max].map((n) => parseInt(n) || 0);
      if (val < min || val > max) {
        input.value = initial;
        input.select();
        return;
      }
      initial = input.value;
      link.href = getUrl(input.value);
      link.click();
    };
    input.addEventListener("focus", () => {
      input.select();
    });
    input.addEventListener("focusout", action);
    input.addEventListener("keypress", (e) => {
      if (e.key == "Enter") {
        action();
      }
    });
  };
  return {
    version: "43.6.1",
    init(arg) {
      const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
      for (const element of elements) {
        try {
          const [helperId, ...args] = JSON.parse(B64Decode(element.getAttribute("data-pagy")));
          if (helperId == "k") {
            augmentKeynav(element, ...args);
          } else if (helperId == "snj") {
            buildNavJs(element, args);
          } else if (helperId == "inj") {
            initInputNavJs(element, args);
          } else if (helperId == "ltj") {
            initLimitTagJs(element, args);
          }
        } catch (err) {
          console.warn(`Pagy.init: %o
%s`, element, err);
        }
      }
    }
  };
})();
