(function () {
  const VARIANTS = ["info", "warning", "error"];
  const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';

  window.Warpbox = window.Warpbox || {};
  let dialogIdCounter = 0;

  function defaultTitle(variant) {
    if (variant === "error") {
      return "Error";
    }
    if (variant === "warning") {
      return "Warning";
    }
    return "Info";
  }

  function normalizeOptions(options, message) {
    if (typeof options === "string") {
      options = { message: options };
    } else {
      options = options || {};
    }
    if (message) {
      options.message = message;
    }
    const variant = VARIANTS.includes(options.variant) ? options.variant : "info";
    return {
      variant,
      title: options.title || defaultTitle(variant),
      message: options.message || "",
      body: options.body || null,
      actions: Array.isArray(options.actions) ? options.actions : [],
      dismissible: options.dismissible !== false,
      closable: options.closable !== false,
      onClose: typeof options.onClose === "function" ? options.onClose : null,
    };
  }

  function focusableElements(container) {
    return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el) => el.offsetParent !== null);
  }

  function dialog(options, message) {
    const config = normalizeOptions(options, message);
    const previouslyFocused = document.activeElement;
    dialogIdCounter += 1;
    const titleId = "warpbox-dialog-title-" + dialogIdCounter;

    const overlay = document.createElement("div");
    overlay.className = "warpbox-dialog-overlay";

    const card = document.createElement("div");
    card.className = "warpbox-dialog warpbox-dialog-" + config.variant;
    card.setAttribute("role", config.variant === "error" ? "alertdialog" : "dialog");
    card.setAttribute("aria-modal", "true");
    card.setAttribute("aria-labelledby", titleId);
    card.setAttribute("tabindex", "-1");

    const head = document.createElement("div");
    head.className = "warpbox-dialog-head";

    const icon = document.createElement("span");
    icon.className = "warpbox-dialog-icon";
    icon.setAttribute("aria-hidden", "true");
    icon.textContent = config.variant === "error" ? "!" : config.variant === "warning" ? "?" : "i";

    const title = document.createElement("h2");
    title.id = titleId;
    title.className = "warpbox-dialog-title";
    title.textContent = config.title;

    head.append(icon, title);

    if (config.closable) {
      const close = document.createElement("button");
      close.type = "button";
      close.className = "warpbox-dialog-close";
      close.setAttribute("aria-label", "Close dialog");
      close.textContent = "x";
      close.addEventListener("click", () => closeDialog());
      head.append(close);
    }

    const body = document.createElement("div");
    body.className = "warpbox-dialog-body";

    if (config.message) {
      const text = document.createElement("p");
      text.className = "warpbox-dialog-message";
      text.textContent = config.message;
      body.append(text);
    }

    if (config.body) {
      const nodes = Array.isArray(config.body) ? config.body : [config.body];
      nodes.forEach((node) => {
        if (node instanceof Node) {
          body.append(node);
        }
      });
    }

    card.append(head, body);

    let autofocusTarget = null;
    if (config.actions.length > 0) {
      const actions = document.createElement("div");
      actions.className = "warpbox-dialog-actions";
      config.actions.forEach((action) => {
        const button = document.createElement("button");
        button.type = "button";
        button.className = "button " + (action.kind === "primary" ? "button-primary" : action.kind === "ghost" ? "button-ghost" : "button-outline");
        button.textContent = action.label || "OK";
        button.addEventListener("click", () => {
          if (typeof action.onClick === "function") {
            action.onClick();
          }
          if (action.dismiss !== false) {
            closeDialog();
          }
        });
        if (action.autofocus) {
          autofocusTarget = button;
        }
        actions.append(button);
      });
      card.append(actions);
    }

    overlay.append(card);
    document.body.append(overlay);
    document.documentElement.classList.add("warpbox-dialog-open");
    window.requestAnimationFrame(() => {
      overlay.classList.add("is-visible");
      (autofocusTarget || card).focus();
    });

    function handleKeydown(event) {
      if (event.key === "Escape") {
        if (config.dismissible) {
          event.preventDefault();
          closeDialog();
        }
        return;
      }
      if (event.key !== "Tab") {
        return;
      }
      const focusable = focusableElements(card);
      if (focusable.length === 0) {
        event.preventDefault();
        return;
      }
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    }

    function handleOverlayClick(event) {
      if (config.dismissible && event.target === overlay) {
        closeDialog();
      }
    }

    document.addEventListener("keydown", handleKeydown, true);
    overlay.addEventListener("click", handleOverlayClick);

    let closed = false;
    function closeDialog() {
      if (closed) {
        return;
      }
      closed = true;
      document.removeEventListener("keydown", handleKeydown, true);
      overlay.removeEventListener("click", handleOverlayClick);
      overlay.classList.remove("is-visible");
      document.documentElement.classList.remove("warpbox-dialog-open");
      window.setTimeout(() => overlay.remove(), 180);
      if (previouslyFocused && typeof previouslyFocused.focus === "function") {
        previouslyFocused.focus();
      }
      if (config.onClose) {
        config.onClose();
      }
    }

    return {
      element: overlay,
      close: closeDialog,
    };
  }

  window.Warpbox.dialog = dialog;

  window.Warpbox.alertDialog = function alertDialog(message, options) {
    const config = (typeof options === "object" && options) || {};
    return new Promise((resolve) => {
      dialog({
        ...config,
        message: typeof message === "string" ? message : config.message,
        actions: [{ label: config.okLabel || "OK", kind: "primary", autofocus: true }],
        onClose: () => {
          if (typeof config.onClose === "function") {
            config.onClose();
          }
          resolve();
        },
      });
    });
  };

  window.Warpbox.confirmDialog = function confirmDialog(message, options) {
    const config = (typeof options === "object" && options) || {};
    return new Promise((resolve) => {
      let settled = false;
      function settle(value) {
        if (settled) {
          return;
        }
        settled = true;
        resolve(value);
      }
      dialog({
        ...config,
        message: typeof message === "string" ? message : config.message,
        actions: [
          { label: config.cancelLabel || "Cancel", kind: "outline", autofocus: true, onClick: () => settle(false) },
          { label: config.confirmLabel || "Confirm", kind: "primary", onClick: () => settle(true) },
        ],
        onClose: () => {
          if (typeof config.onClose === "function") {
            config.onClose();
          }
          settle(false);
        },
      });
    });
  };

  window.Warpbox.promptDialog = function promptDialog(message, options) {
    const config = (typeof options === "object" && options) || {};
    return new Promise((resolve) => {
      let settled = false;
      function settle(value) {
        if (settled) {
          return;
        }
        settled = true;
        resolve(value);
      }

      const field = document.createElement("input");
      field.type = config.inputType || "text";
      field.className = "warpbox-dialog-field";
      if (config.placeholder) {
        field.placeholder = config.placeholder;
      }
      if (typeof config.value === "string") {
        field.value = config.value;
      }

      let controller = null;
      field.addEventListener("keydown", (event) => {
        if (event.key === "Enter") {
          event.preventDefault();
          settle(field.value);
          if (controller) {
            controller.close();
          }
        }
      });

      controller = dialog({
        ...config,
        message: typeof message === "string" ? message : config.message,
        body: field,
        actions: [
          { label: config.cancelLabel || "Cancel", kind: "outline", onClick: () => settle(null) },
          { label: config.okLabel || "OK", kind: "primary", onClick: () => settle(field.value) },
        ],
        onClose: () => {
          if (typeof config.onClose === "function") {
            config.onClose();
          }
          settle(null);
        },
      });

      window.requestAnimationFrame(() => field.focus());
    });
  };
})();
