// 统一轮询钩子：interval + 存活标志 + 卸载清理 + 在途去重。
// 用法：usePoll(async () => {...; return 'stop' 以提前停止}, intervalMs, deps, enabled)
// - fn 在每个 tick 调用，await 期间组件卸载则丢弃结果（不 setState）。
// - fn 返回 'stop'（或经 alive() 自行判断）时停止本轮轮询，避免拿到终态后还永久 1Hz 打后端。
// - 同一时刻只有一个在途请求；上一次未返回则跳过本 tick，避免请求堆积/竞态。
// - deps 变化或卸载时清理定时器并失活，await 中的回调不再写状态。
import { useEffect, useRef } from 'react';

export function usePoll(fn, intervalMs, deps = [], enabled = true) {
  // 用 ref 持有最新 fn，避免把 fn 放进 deps 造成每次渲染重启轮询。
  const fnRef = useRef(fn);
  fnRef.current = fn;

  useEffect(() => {
    if (!enabled) return undefined;
    let alive = true;
    let inFlight = false;
    let timer = null;

    const stop = () => {
      alive = false;
      if (timer) { clearInterval(timer); timer = null; }
    };

    const tick = async () => {
      if (!alive || inFlight) return;
      inFlight = true;
      try {
        const r = await fnRef.current(() => alive);
        // await 期间组件可能已卸载/deps 变化：丢弃结果。
        if (!alive) return;
        if (r === 'stop') stop();
      } finally {
        inFlight = false;
      }
    };

    // 立即触发一次，再按间隔轮询。
    tick();
    timer = setInterval(tick, intervalMs);
    return stop;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [intervalMs, enabled, ...deps]);
}
