(() => {
  const buttons = new Set();

  const getViews = (button) => Array.from(button.querySelectorAll("[data-state-view]"));

  const setState = (button, state, options = {}) => {
    if (!button) return;
    const requestedState = state || button.dataset.defaultState || "idle";
    const availableStates = new Set(getViews(button).map((view) => view.dataset.stateView));
    const nextState = availableStates.has(requestedState)
      ? requestedState
      : button.dataset.defaultState || "idle";
    const busyState = button.dataset.loadingState || "loading";
    const isBusy = nextState === busyState || options.busy === true;

    button.dataset.state = nextState;
    button.setAttribute("aria-busy", isBusy ? "true" : "false");

    getViews(button).forEach((view) => {
      const isVisible = view.dataset.stateView === nextState;
      view.dataset.stateHidden = isVisible ? "false" : "true";
      view.setAttribute("aria-hidden", isVisible ? "false" : "true");
    });

    if (button.dataset.disableWhileBusy === "true") {
      button.disabled = isBusy;
    }
  };

  const reset = (button) => {
    setState(button, button?.dataset.defaultState || "idle");
  };

  const scheduleReset = (button) => {
    const delay = Number(button?.dataset.resetDelay || 0);
    if (delay > 0) window.setTimeout(() => reset(button), delay);
  };

  const initButton = (button) => {
    if (buttons.has(button)) return;
    buttons.add(button);
    button.classList.add("lumi-state-btn");
    setState(button, button.dataset.state || button.dataset.defaultState || "idle");
  };

  document.querySelectorAll("[data-lumi-state-button]").forEach(initButton);

  document.addEventListener("submit", (event) => {
    const submitter = event.submitter;
    if (!submitter?.matches?.("[data-lumi-state-button]")) return;
    initButton(submitter);
    setState(submitter, submitter.dataset.loadingState || "loading", { busy: true });
  }, true);

  window.LumiStateButton = {
    init: initButton,
    setState,
    reset,
    success(button) {
      setState(button, button?.dataset.successState || "success");
      scheduleReset(button);
    },
    error(button) {
      setState(button, button?.dataset.errorState || "error");
      scheduleReset(button);
    }
  };
})();
