/**
 * Runtime diagnostic helpers for best-effort operations.
 *
 * Many runtime operations (postMessage to a parent frame, `media.play()` /
 * `pause()` / `currentTime=`, timeline `seek()`, anime.js feature detection,
 * etc.) can throw under perfectly normal conditions: the parent frame is
 * cross-origin, autoplay is denied, the media element was just removed from
 * the DOM, the timeline has been disposed, the host page does not include
 * anime.js. The right behaviour in each case is "tried, didn't work, move
 * on" — but emitting nothing makes silent failures invisible to anyone
 * debugging a genuinely broken composition, and the bare `catch {}` shape
 * also trips strict lint configurations on the inlined runtime IIFE.
 *
 * `swallow(label, err)` is the single funnel for these intentional silences.
 * It dispatches to:
 *
 *   - `console.debug` with the label, the error, and a `[hyperframes]` prefix
 *     when `window.__hfDebug === true` (or the legacy `__HYPERFRAMES_DEBUG`
 *     env-style global). Quiet by default; flip the flag in DevTools when
 *     hunting a regression.
 *   - A custom `__hf.onSwallowed` handler if installed — lets the studio /
 *     embeddings collect runtime swallow events without polluting the page
 *     console.
 *
 * Production behaviour without either flag set: completely silent, just
 * like the original empty `catch {}`. The shape is also lint-clean — the
 * helper call is a real statement, so no `no-empty` warnings ship in the
 * inlined IIFE.
 */
export interface SwallowedEvent {
  /** Short, descriptive label naming the operation that failed. */
  label: string;
  /** The thrown value (often an Error, but JS allows anything). */
  error: unknown;
}

interface HFDebugSurface {
  __hfDebug?: boolean;
  __HYPERFRAMES_DEBUG?: boolean;
  __hf?: {
    onSwallowed?: (event: SwallowedEvent) => void;
  };
}

export function swallow(label: string, error?: unknown): void {
  if (typeof window === "undefined") return;
  const w = window as unknown as HFDebugSurface;

  const handler = w.__hf?.onSwallowed;
  if (handler) {
    try {
      handler({ label, error });
    } catch (handlerError) {
      // Don't recurse into swallow() — a consumer hook that throws
      // shouldn't be allowed to take down the runtime, and routing the
      // failure back through swallow() would loop. Drop on the floor;
      // the original error already had its surface above.
      void handlerError;
    }
  }

  if (w.__hfDebug || w.__HYPERFRAMES_DEBUG) {
    // eslint-disable-next-line no-console -- intentional debug surface
    console.debug(`[hyperframes] ${label} swallowed:`, error);
  }
}
