import { useRef } from 'react'

const NOT_SET = Symbol('NOT_SET')

/**
 * Hook to get the previous value of a state or prop. Returns an object with:
 *
 * - `hasChanged`: Whether the value has changed since the previous render / call to this function.
 * - `value`: The value that was passed to the hook in the previous render (`undefined` on first
 *   render).
 * - `lastDifferentValue`: The most recent value that was different from the current value.
 *
 * @example
 *
 * ```ts
 * const previous = usePrevious(someValue)
 * if (previous.hasChanged) {
 *   // Value changed from `previous.value` to `someValue`
 * }
 * ```
 */
export function usePrevious<T>(value: T) {
  const previousRenderValueRef = useRef<T | typeof NOT_SET>(NOT_SET)
  const lastDifferentValueRef = useRef<T | typeof NOT_SET>(NOT_SET)

  const previousRenderValue = previousRenderValueRef.current
  const hasChanged = previousRenderValueRef.current !== NOT_SET && previousRenderValue !== value
  if (hasChanged) {
    lastDifferentValueRef.current = previousRenderValue
  }
  previousRenderValueRef.current = value

  return {
    hasChanged,
    value: previousRenderValueRef.current !== NOT_SET ? (previousRenderValue as T) : undefined,
    lastDifferentValue:
      lastDifferentValueRef.current !== NOT_SET ? (lastDifferentValueRef.current as T) : undefined,
  }
}
