import { useCallback, useSyncExternalStore } from 'react';
import { WeBObservableMapRead } from '../../buttercup/observable';

/**
 * Subscribe to a WeBObservableMap (the library's records, record types,
 * connections and connection types) and re-render when it changes.
 *
 * Returns both the item map and its id list, since a component usually wants
 * to iterate in order as well as look up by id.
 *
 * Two subscriptions, one per container, each reading live state. `items` and
 * `ids` change on different events — an `update()` never touches `ids` — and
 * the observable map replaces each exactly when it changes, so both are stable
 * between changes and safe as a dependency or a memo key. Caching the pair in
 * a ref instead was tried and reverted: the snapshot went stale the moment
 * the invalidation check sat anywhere but inside `getSnapshot`, which froze
 * every consumer after mount.
 *
 * The parameter is the observable map's read type, not `WeBObservableMapBase`, so a
 * node map — a `WeBObservableMutatingMap`, which calls `update()` every frame of a
 * drag — won't compile here. `kind` is the whole of what turns it away:
 * `'map'` against `'mutatingMap'`. The two maps share their mutators, so
 * nothing else distinguishes them.
 *
 * @param observable - the map to observe
 * @return the current items and ids
 */
export const useObservableMap = < Item extends object >(
	observable: WeBObservableMapRead< Item >
) => {
	const subscribe = useCallback(
		( onChange: () => void ) => observable.observe( onChange ),
		[ observable ]
	);

	return {
		items: useSyncExternalStore( subscribe, () => observable.items ),
		ids: useSyncExternalStore( subscribe, () => observable.ids ),
	};
};
