import { onBeforeUnmount } from 'vue'
interface CallbackArgs {
  progress: number
  timeElapsed: number
  timestamp: DOMHighResTimeStamp
}

export function useRaf(callback: (args: CallbackArgs) => void, duration: number, immediate = true) {
  let requestID: number | null
  let progress: number | null
  let previousTimestamp = 0
  let totalDelta = 0
  let isActive = false

  function loop(timestamp: DOMHighResTimeStamp) {
    if (!isActive) {
      isActive = true
      previousTimestamp = timestamp
    }

    totalDelta = totalDelta + timestamp - previousTimestamp

    progress = totalDelta / duration

    if (totalDelta > duration && requestID) {
      cancelAnimationFrame(requestID)
      requestID = null
      isActive = false

      return
    }

    callback({ timestamp, timeElapsed: totalDelta, progress: parseFloat(progress.toFixed(2)) })

    previousTimestamp = timestamp
    requestID = requestAnimationFrame(loop)
  }

  function start() {
    if (isActive) return
    requestID = requestAnimationFrame(loop)
  }

  function pause() {
    if (requestID) {
      cancelAnimationFrame(requestID)
      isActive = false
    }
  }

  function reset() {
    if (requestID) {
      cancelAnimationFrame(requestID)
    }
    isActive = false
    progress = null
    previousTimestamp = 0
    totalDelta = 0
    isActive = false
    requestID = null

    callback({ timestamp: 0, timeElapsed: 0, progress: 0 })
  }

  if (immediate) start()
  onBeforeUnmount(reset)

  return {
    start,
    pause,
    reset
  }
}