import React from 'react'
import PropTypes from 'prop-types'
import { ScrollView } from 'react-native'
import debounce from 'lodash.debounce'

const DEBOUNCE_MS = 100

/**
 * A wrapper for ScrollView that supports an `onScrollEnd` function.
 *
 * React Native Web hasn't got around to implementing any scroll end handlers yet,
 * so we need to work around it with debouncing on `onScroll`. See:
 * https://github.com/necolas/react-native-web/issues/1021
 */
export const ScrollViewEnd = React.forwardRef(({ onScrollEnd, onScroll = null, ...props }, ref) => {
  // Return debounced function directly from useCallback so it has .cancel method etc.
  // Linter complains this stops it automatically scanning the deps, but we can check them manually.
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const debounceScrollEnd = React.useCallback(
    debounce((event) => onScrollEnd(event), DEBOUNCE_MS),
    [onScrollEnd]
  )

  // Call any onScroll handler immediately, and any onScrollEnd handler after 100ms of no scrolling
  const handleScroll = (event) => {
    if (typeof onScroll === 'function') onScroll(event)
    if (typeof onScrollEnd === 'function') debounceScrollEnd(event)
  }

  // Cancel any lingering debounce timeouts on dismount
  React.useEffect(() => debounceScrollEnd.cancel)

  return (
    <ScrollView
      ref={ref}
      {...props}
      onScroll={handleScroll}
      scrollEventThrottle={DEBOUNCE_MS / 2}
    />
  )
})
ScrollViewEnd.displayName = 'ScrollViewEnd'

ScrollViewEnd.propTypes = {
  onScrollEnd: PropTypes.func.isRequired,
  onScroll: PropTypes.func
}
