import { useCallback, useRef, useState } from 'react'

export function useControlled<T, OnChangeValue extends T = T, OnChangeArgs extends unknown[] = []>(
  controlledValue: T | undefined,
  defaultValue: T,
  onChange?: (value: OnChangeValue, ...args: OnChangeArgs) => void,
) {
  const onChangeRef = useRef(onChange)
  onChangeRef.current = onChange

  const [uncontrolledValue, setUncontrolledValue] = useState(
    controlledValue !== undefined ? controlledValue : defaultValue,
  )

  const value = controlledValue !== undefined ? controlledValue : uncontrolledValue
  const setValue = useCallback(
    (newValue: OnChangeValue, ...args: OnChangeArgs) => {
      if (newValue === value) return
      onChangeRef.current?.(newValue, ...args)
      if (controlledValue === undefined) {
        setUncontrolledValue(newValue)
      }
    },
    [controlledValue, value],
  )

  return [value, setValue] as const
}
