import { onBeforeUnmount, onMounted, ref } from 'vue'

interface PollingOptions {
  /** 启动后是否立即执行一次，默认立即执行。 */
  immediate?: boolean
  /** 页面不可见时是否暂停，默认暂停。 */
  pauseWhenHidden?: boolean
  /** 轮询函数抛错时的可选回调。 */
  onError?: (error: unknown) => void
}

/**
 * 轮询 composable
 * 串行轮询：上一轮完成后才安排下一轮，避免慢请求重叠和旧响应覆盖。
 * 页面进入后台时自动暂停，恢复可见后立即刷新；组件卸载时自动清理。
 */
export function usePolling(
  fn: () => void | Promise<void>,
  interval: number | (() => number) = 5000,
  options: PollingOptions = {},
) {
  const { immediate = true, pauseWhenHidden = true, onError } = options
  const isActive = ref(false)
  const isRunning = ref(false)
  let timer: ReturnType<typeof setTimeout> | null = null

  function clearTimer() {
    if (!timer) return
    clearTimeout(timer)
    timer = null
  }

  function schedule() {
    clearTimer()
    if (!isActive.value) return
    if (pauseWhenHidden && document.hidden) return
    const delay = typeof interval === 'function' ? interval() : interval
    timer = setTimeout(() => void run(), Math.max(0, delay))
  }

  async function run() {
    clearTimer()
    if (!isActive.value || isRunning.value) return
    if (pauseWhenHidden && document.hidden) return

    isRunning.value = true
    try {
      await fn()
    } catch (error) {
      onError?.(error)
    } finally {
      isRunning.value = false
      schedule()
    }
  }

  function stop() {
    isActive.value = false
    clearTimer()
  }

  function start() {
    if (isActive.value) return
    isActive.value = true
    if (immediate) void run()
    else schedule()
  }

  function handleVisibilityChange() {
    if (!pauseWhenHidden || !isActive.value) return
    if (document.hidden) clearTimer()
    else void run()
  }

  onMounted(() => document.addEventListener('visibilitychange', handleVisibilityChange))
  onBeforeUnmount(() => {
    stop()
    document.removeEventListener('visibilitychange', handleVisibilityChange)
  })

  return { start, stop, run, isActive, isRunning }
}
