(function () {
  const toasts = new Map();
  const order = [];
  let counter = 0;
  let container = null;

  const DEFAULT_DURATION = 3500;
  const TYPE_ICON = {
    loading: "…",
    info: "i",
    success: "✓",
    error: "!",
  };

  function ensureContainer() {
    if (container && document.body.contains(container)) return container;
    container = document.createElement("div");
    container.className = "app-toast-container";
    container.setAttribute("aria-live", "polite");
    container.setAttribute("aria-atomic", "false");
    document.body.appendChild(container);
    return container;
  }

  function parseDuration(options) {
    if (options?.sticky) return Infinity;
    if (options?.duration == null) return DEFAULT_DURATION;
    const value = options.duration;
    if (value === Infinity || value === Number.POSITIVE_INFINITY) return Infinity;
    const n = Number(value);
    return Number.isFinite(n) && n >= 0 ? n : DEFAULT_DURATION;
  }

  function normalizeMessage(value, fallback) {
    const text = String(value == null ? "" : value).trim();
    return text || fallback;
  }

  function createToastNode(id) {
    const node = document.createElement("section");
    node.className = "app-toast app-toast--info";
    node.dataset.toastId = id;
    node.tabIndex = 0;

    const icon = document.createElement("span");
    icon.className = "app-toast__icon";

    const content = document.createElement("div");
    content.className = "app-toast__content";

    const title = document.createElement("p");
    title.className = "app-toast__title";

    const description = document.createElement("p");
    description.className = "app-toast__description";

    const actions = document.createElement("div");
    actions.className = "app-toast__actions";

    const actionBtn = document.createElement("button");
    actionBtn.type = "button";
    actionBtn.className = "app-toast__action";

    const closeBtn = document.createElement("button");
    closeBtn.type = "button";
    closeBtn.className = "app-toast__close";
    closeBtn.setAttribute("aria-label", "Cerrar notificación");
    closeBtn.textContent = "×";

    actions.appendChild(actionBtn);
    actions.appendChild(closeBtn);

    content.appendChild(title);
    content.appendChild(description);
    content.appendChild(actions);

    node.appendChild(icon);
    node.appendChild(content);

    closeBtn.addEventListener("click", function () {
      dismiss(id);
    });

    return {
      id,
      node,
      icon,
      title,
      description,
      actions,
      actionBtn,
      closeBtn,
      timer: null,
      actionHandler: null,
    };
  }

  function clearTimer(toast) {
    if (toast?.timer) {
      globalThis.clearTimeout(toast.timer);
      toast.timer = null;
    }
  }

  function attachAction(toast, options) {
    const label = normalizeMessage(options?.actionLabel, "");
    const handler = options && typeof options.onAction === "function" ? options.onAction : null;
    const dismissOnAction = options?.dismissOnAction !== false;

    toast.actionBtn.style.display = label && handler ? "inline-flex" : "none";
    toast.actionBtn.textContent = label;

    if (toast.actionHandler) {
      toast.actionBtn.removeEventListener("click", toast.actionHandler);
      toast.actionHandler = null;
    }

    if (label && handler) {
      toast.actionHandler = function () {
        try {
          handler();
        } finally {
          if (dismissOnAction) dismiss(toast.id);
        }
      };
      toast.actionBtn.addEventListener("click", toast.actionHandler);
    }
  }

  function updateToast(toast, message, options) {
    const opts = options || {};
    const type = normalizeMessage(opts.type, "info").toLowerCase();
    const resolvedType = TYPE_ICON[type] ? type : "info";
    const description = normalizeMessage(opts.description, "");
    const duration = parseDuration(opts);

    toast.node.className = "app-toast app-toast--" + resolvedType;
    toast.icon.textContent = TYPE_ICON[resolvedType] || TYPE_ICON.info;
    toast.title.textContent = normalizeMessage(message, "Actualización de proceso");

    toast.description.textContent = description;
    toast.description.style.display = description ? "block" : "none";

    attachAction(toast, opts);

    clearTimer(toast);
    if (duration !== Infinity) {
      toast.timer = globalThis.setTimeout(function () {
        dismiss(toast.id);
      }, duration);
    }
  }

  function upsert(id, message, options) {
    const root = ensureContainer();
    let toast = toasts.get(id);
    if (!toast) {
      toast = createToastNode(id);
      toasts.set(id, toast);
      order.push(id);
      root.appendChild(toast.node);
      requestAnimationFrame(function () {
        toast.node.classList.add("is-visible");
      });
    }
    updateToast(toast, message, options);
    return id;
  }

  function nextId() {
    counter += 1;
    return "app-toast-" + String(Date.now()) + "-" + String(counter);
  }

  function show(message, options) {
    const id = options?.id ? String(options.id) : nextId();
    return upsert(id, message, options || {});
  }

  function start(message, options) {
    return show(message || "Iniciando proceso...", {
      ...options,
      type: "loading",
      sticky: true,
      duration: Infinity,
    });
  }

  function progress(id, message, options) {
    return upsert(String(id), message || "Proceso en curso...", { ...options, type: "loading",
      sticky: true,
      duration: Infinity,});
  }

  function success(id, message, options) {
    return upsert(String(id), message || "Proceso completado", {
      ...options,
      type: "success",
      sticky: false,
      duration: options?.duration || 4200,
    });
  }

  function error(id, message, options) {
    return upsert(String(id), message || "Ocurrió un error", {
      ...options,
      type: "error",
      sticky: options && typeof options.sticky === "boolean" ? options.sticky : false,
      duration: options?.duration ?? 7000,
    });
  }

  function dismiss(id) {
    if (id === undefined || id === null) {
      order.slice().forEach(function (toastId) {
        dismiss(toastId);
      });
      return;
    }

    const key = String(id);
    const toast = toasts.get(key);
    if (!toast) return;

    clearTimer(toast);

    const removeFromDom = function () {
      if (toast.actionHandler) {
        toast.actionBtn.removeEventListener("click", toast.actionHandler);
        toast.actionHandler = null;
      }
      if (toast.node?.parentNode) {
        toast.node.parentNode.removeChild(toast.node);
      }
    };

    toast.node.classList.remove("is-visible");
    toast.node.classList.add("is-leaving");

    globalThis.setTimeout(removeFromDom, 180);
    toasts.delete(key);
    const index = order.indexOf(key);
    if (index >= 0) order.splice(index, 1);
  }

  function dismissLatest() {
    const lastId = order.at(-1);
    if (lastId) dismiss(lastId);
  }

  function init() {
    ensureContainer();
    if (!globalThis.__appToastEscListener) {
      globalThis.__appToastEscListener = true;
      document.addEventListener("keydown", function (event) {
        if (event.key === "Escape") {
          dismissLatest();
        }
      });
    }
  }

  document.addEventListener("DOMContentLoaded", init);

  globalThis.AppToast = {
    init,
    show,
    start,
    progress,
    success,
    error,
    dismiss,
  };
})();
