import { useCallback, useEffect, useRef } from 'react';

/** Во время drag шлёт onMove не чаще одного раза за кадр (для live-синхронизации презентации). */
export function useLiveDragBroadcast(
  onMove: ((id: string, nx: number, ny: number) => void) | undefined,
  id: string,
): {
  schedule: (nx: number, ny: number) => void;
  flush: (nx: number, ny: number) => void;
} {
  const rafRef = useRef(0);
  const pendingRef = useRef<{ nx: number; ny: number } | null>(null);
  const onMoveRef = useRef(onMove);
  onMoveRef.current = onMove;
  const idRef = useRef(id);
  idRef.current = id;

  useEffect(
    () => () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    },
    [],
  );

  const schedule = useCallback((nx: number, ny: number) => {
    if (!onMoveRef.current) return;
    pendingRef.current = { nx, ny };
    if (rafRef.current) return;
    rafRef.current = requestAnimationFrame(() => {
      rafRef.current = 0;
      const pending = pendingRef.current;
      const cb = onMoveRef.current;
      if (!pending || !cb) return;
      cb(idRef.current, pending.nx, pending.ny);
    });
  }, []);

  const flush = useCallback((nx: number, ny: number) => {
    if (rafRef.current) {
      cancelAnimationFrame(rafRef.current);
      rafRef.current = 0;
    }
    pendingRef.current = null;
    onMoveRef.current?.(idRef.current, nx, ny);
  }, []);

  return { schedule, flush };
}

/** Во время resize шлёт onResize не чаще одного раза за кадр. */
export function useLiveResizeBroadcast(
  onResize: ((id: string, sizeN: number) => void) | undefined,
  id: string,
): {
  schedule: (sizeN: number) => void;
  flush: (sizeN: number) => void;
} {
  const rafRef = useRef(0);
  const pendingRef = useRef<number | null>(null);
  const onResizeRef = useRef(onResize);
  onResizeRef.current = onResize;
  const idRef = useRef(id);
  idRef.current = id;

  useEffect(
    () => () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    },
    [],
  );

  const schedule = useCallback((sizeN: number) => {
    if (!onResizeRef.current) return;
    pendingRef.current = sizeN;
    if (rafRef.current) return;
    rafRef.current = requestAnimationFrame(() => {
      rafRef.current = 0;
      const pending = pendingRef.current;
      const cb = onResizeRef.current;
      if (pending === null || !cb) return;
      cb(idRef.current, pending);
    });
  }, []);

  const flush = useCallback((sizeN: number) => {
    if (rafRef.current) {
      cancelAnimationFrame(rafRef.current);
      rafRef.current = 0;
    }
    pendingRef.current = null;
    onResizeRef.current?.(idRef.current, sizeN);
  }, []);

  return { schedule, flush };
}
