import { useRef } from 'react'

import { useEventListener, useToggle } from 'hooks'

const getNormalizedProgress = (fraction: number) => {
  if (fraction > 1) return 1
  if (fraction < 0) return 0
  return fraction
}

type Args = {
  onChange: (progress: number, seeking: boolean) => void,
}

export const useSlider = ({ onChange }: Args) => {
  const ref = useRef<HTMLDivElement>(null)
  const lastProgress = useRef(0)
  const {
    close: setMouseDown,
    isOpen: isMouseUp,
    open: setMouseUp,
  } = useToggle(true)

  const handleProgress = (mouseX: number, seeking: boolean) => {
    const track = ref.current
    if (!track) return

    const x = mouseX - track.getBoundingClientRect().left
    const progress = getNormalizedProgress(x / track.offsetWidth)
    lastProgress.current = progress
    onChange(progress, seeking)
  }

  const mouseDownListener = ({ clientX, target }: MouseEvent) => {
    const track = ref.current
    if (target === track || track?.contains(target as Node)) {
      setMouseDown()
      handleProgress(clientX, !isMouseUp)
    }
  }

  const mouseUpListener = () => {
    if (!isMouseUp) {
      onChange(lastProgress.current, false)
      setMouseUp()
      lastProgress.current = 0
    }
  }

  const mouseMoveListener = (e: MouseEvent) => {
    if (isMouseUp) return
    handleProgress(e.clientX, !isMouseUp)
  }

  useEventListener({
    callback: mouseDownListener,
    event: 'mousedown',
  })
  useEventListener({
    callback: mouseUpListener,
    event: 'mouseup',
  })
  useEventListener({
    callback: mouseMoveListener,
    event: 'mousemove',
  })

  return ref
}
