import { createContext, createEffect, useContext } from "solid-js";
import { readOption } from "../internals/maybe-accessor.jsx";
import { SNAPSHOT_KEYS, snapshotKeys } from "../internals/observability/snapshot.jsx";
import { createToastStore } from "./toast-store.jsx";

/**
 * Options for {@link createToast}.
 *
 * The queue is internally owned — `timeout` / `limit` configure it but the
 * consumer does not hold signals for them. Unlike `createTabs`/etc the toast
 * primitive owns internal state because the queue IS the implementation (it
 * is not a consumer-controlled value; the consumer drives it via `add` / `close`
 * / `update` imperatives).
 */

/**
 * Public API returned by {@link createToast}.
 */

const ToastContext = createContext(null);

/**
 * Read the nearest {@link ToastApi} provided by `c.Provider`. Throws if
 * called outside a Provider.
 */
export function useToast() {
  const ctx = useContext(ToastContext);
  if (ctx == null) {
    throw new Error("Base UI: useToast() must be called inside a <c.Provider>.");
  }
  return ctx;
}

/**
 * Solid-native headless toast primitive. Owns the queue, timers, and
 * lifecycle bookkeeping. The consumer drives the queue via `add` / `close` /
 * `update` / `promise` imperatives and reads reactive state (`toasts`,
 * `expanded`, `hovering`, `focused`, `isEmpty`) through accessors.
 *
 * Internal state IS appropriate here: the queue is implementation detail
 * (not a consumer-controlled value). `timeout` / `limit` configure the store
 * but the consumer never holds the backing signals.
 *
 * Callbacks (`onValueChange` etc.) are not part of this surface because there
 * is no discrete "value" the consumer needs to mirror — the consumer observes
 * the queue reactively via `toasts()`. The `onClose` / `onRemove` hooks on
 * individual `ToastObject`s serve per-toast lifecycle needs.
 */
export function createToast(options = {}) {
  const initialTimeout = readOption(options.timeout) ?? 5000;
  const initialLimit = readOption(options.limit) ?? 3;
  const store = createToastStore({
    timeout: initialTimeout,
    limit: initialLimit
  });

  // Sync timeout/limit into the store when the accessor values change.
  // Split compute/apply (RFC 02) so reads and writes stay in separate scopes.
  createEffect(() => readOption(options.timeout) ?? 5000, next => {
    store.setTimeoutOption(next);
  });
  createEffect(() => readOption(options.limit) ?? 3, next => {
    store.setLimitOption(next);
  });

  // Forward external manager events into the store. Returns cleanup so the
  // apply phase can unsubscribe without needing `onCleanup` (the apply runs
  // in an unowned scope where `onCleanup` would trip NO_OWNER_CLEANUP).
  createEffect(() => readOption(options.toastManager), manager => {
    if (!manager) return undefined;
    const unsubscribe = manager[" subscribe"](event => {
      const {
        action,
        options: opts
      } = event;
      const id = opts.id;
      if (action === "promise" && opts.promise && "loading" in opts && "success" in opts && "error" in opts) {
        const promiseOptions = {
          loading: opts.loading,
          success: opts.success,
          error: opts.error,
          setPromise: opts.setPromise
        };
        store.promiseToast(opts.promise, promiseOptions);
      } else if (action === "update" && id) {
        store.updateToast(id, opts);
      } else if (action === "close") {
        store.closeToast(id);
      } else {
        store.addToast(opts);
      }
    });
    return unsubscribe;
  });
  const api = {
    toasts: store.toasts,
    expanded: store.expanded,
    hovering: store.hovering,
    focused: store.focused,
    isEmpty: store.isEmpty,
    add(addOptions) {
      return store.addToast(addOptions);
    },
    close(id) {
      store.closeToast(id);
    },
    update(id, updateOptions) {
      store.updateToast(id, updateOptions);
    },
    promise(value, promiseOptions) {
      return store.promiseToast(value, promiseOptions);
    },
    get store() {
      return store;
    },
    Provider: props => <ToastContext value={api}>{props.children}</ToastContext>
  };
  api[SNAPSHOT_KEYS] = TOAST_SNAPSHOT_KEYS;
  return api;
}
const TOAST_SNAPSHOT_KEYS = snapshotKeys("toasts", "expanded", "hovering", "focused", "isEmpty");
//# sourceMappingURL=create-toast.jsx.map
