import { useEffect, useSyncExternalStore, type ReactNode } from "react";

/**
 * External store for the page's header title + actions used by the
 * "standard layout" (settings, team, tools, draft-queue). The inbox
 * view has its own bespoke header and ignores this store.
 *
 * We use an external store (not React context) so that pages can mount
 * ReactNode without subscribing — subscribing would re-render and create
 * new JSX every render, which would update the store again, infinite-looping.
 */

type Listener = () => void;

let currentTitle: ReactNode = null;
let currentActions: ReactNode = null;
const listeners = new Set<Listener>();

function notify() {
  for (const l of listeners) l();
}

function subscribe(l: Listener): () => void {
  listeners.add(l);
  return () => {
    listeners.delete(l);
  };
}

export function useHeaderTitle(): ReactNode {
  return useSyncExternalStore(
    subscribe,
    () => currentTitle,
    () => currentTitle,
  );
}

export function useHeaderActions(): ReactNode {
  return useSyncExternalStore(
    subscribe,
    () => currentActions,
    () => currentActions,
  );
}

export function useSetPageTitle(node: ReactNode) {
  useEffect(() => {
    currentTitle = node;
    notify();
    return () => {
      currentTitle = null;
      notify();
    };
  });
}

export function useSetHeaderActions(node: ReactNode) {
  useEffect(() => {
    // Callers may pass a fresh-but-equivalent node (e.g. `null` from a
    // conditional) on every render; only broadcast when the reference the
    // store holds actually changes so unrelated re-renders of the caller
    // don't force every header subscriber to re-render too.
    if (currentActions !== node) {
      currentActions = node;
      notify();
    }
    return () => {
      if (currentActions === node) {
        currentActions = null;
        notify();
      }
    };
  });
}
