import type { Dispatch, SetStateAction } from 'react'
import { useCallback, useState } from 'react'

import isFunction from 'lodash/isFunction'

type Updater<T> = (prevState: T) => T
const isUpdater = <T extends object>(value: any): value is Updater<T> => (
  isFunction(value)
)

/**
 * Дженерик для создания типа сеттера, получает тип стейта как параметр
 */
export type SetPartialState<T> = Dispatch<SetStateAction<Partial<T>>>

/**
 * Хук на основе useState с возможносьтю мержа стейта как в классовых компонентах
 */
export const useObjectState = <T extends object>(initialState: T) => {
  const [state, setState] = useState(initialState)

  const setPlayerState: SetPartialState<T> = useCallback((newStateOrUpdater) => {
    setState((oldState) => {
      const newState = isUpdater(newStateOrUpdater)
        ? newStateOrUpdater(oldState)
        : newStateOrUpdater
      // если updater функция вернула старый стейт то и здесь
      // возвращаем тот же стейт чтобы избежать лишнего ререндера
      if (newState === oldState) return oldState

      return { ...oldState, ...newState }
    })
  }, [])

  return [state, setPlayerState] as const
}
