import React from 'react'
import {
  getLocalStorageItem,
  removeLocalStorageItem,
  setLocalStorageItem
} from 'utils'

const useLocalStorageSubscribe = (callback: () => void) => {
  window.addEventListener('storage', callback)
  return () => window.removeEventListener('storage', callback)
}

export function useLocalStorage<T>(
  key: string,
  initialValue: T
): [T, React.Dispatch<React.SetStateAction<T>>] {
  const getSnapshot = () => getLocalStorageItem(key, initialValue)

  const data = React.useSyncExternalStore(useLocalStorageSubscribe, getSnapshot)

  const setState: React.Dispatch<React.SetStateAction<T>> = React.useCallback(
    (v: React.SetStateAction<T>) => {
      try {
        const nextState =
          typeof v === 'function'
            ? (v as (prevState: T) => T)(JSON.parse(data))
            : v

        if (nextState === undefined || nextState === null) {
          removeLocalStorageItem(key)
        } else {
          setLocalStorageItem(key, JSON.stringify(nextState))
        }
      } catch (e) {
        console.warn(e)
      }
    },
    [key, data]
  )

  React.useEffect(() => {
    // Set local storage only when it's empty
    const data = window.localStorage.getItem(key)
    if (data === null) {
      setLocalStorageItem(key, JSON.stringify(initialValue))
    }
  }, [key, initialValue])

  return [JSON.parse(data) as T, setState]
}
