/**
 * Returns a debounced version of fn that delays invocation until after
 * `delay` ms have elapsed since the last call. The returned function
 * exposes a `cancel()` method that DROPS (does not flush) the pending
 * trailing invocation — essential when the host context (a destroyed
 * component, an unmounted editor) shouldn't fire the trailing call.
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function debounce<T extends (...args: any[]) => void>(
	fn: T,
	delay: number
): T & { cancel: () => void } {
	let timer: ReturnType<typeof setTimeout> | undefined;
	const wrapped = ((...args: Parameters<T>) => {
		if (timer !== undefined) clearTimeout(timer);
		timer = setTimeout(() => fn(...args), delay);
	}) as T & { cancel: () => void };
	wrapped.cancel = () => {
		if (timer !== undefined) {
			clearTimeout(timer);
			timer = undefined;
		}
	};
	return wrapped;
}
