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

import { queryParamStorage } from 'features/QueryParamsStorage'

import {
  dateReplacer,
  readStorageInitialValue,
} from './helpers'

const defaultValidator = () => true

type Args<T> = {
  defaultValue: T,
  key: string,

  /**
   * функция для валидации полученного значения из стора
   * если значение не валидно то используется defaultValue.
   * Если не передан валидатор то полученное значение из стореджа
   * считается валидным.
   */
  validator?: (value: T) => boolean,
}

/**
 * Хук высшего порядка, получает сторедж
 * и возвращает хук работающий с данным стореджем
 * Хук считывает значение из стора и использует как начальное значение стейта,
 * при вызове сеттера обновляется сторедж и реакт стейет
 */
const createHook = (storage: Storage) => (
  <T extends any>({
    defaultValue,
    key,
    validator = defaultValidator,
  }: Args<T>) => {
    const getInitialState = () => {
      const storeValue = readStorageInitialValue(storage, key)
      const isValid = validator(storeValue)
      return isValid ? storeValue : defaultValue
    }

    const [state, setState] = useState<T>(getInitialState)

    const setStateAndSave = useCallback((value: T) => {
      storage.setItem(key, JSON.stringify(value, dateReplacer))
      setState(value)
    }, [key])

    useEffect(() => {
      const storeValue = readStorageInitialValue(storage, key)
      const isValid = validator(storeValue)
      if (!isValid) {
        storage.removeItem(key)
      }
    }, [key, validator])

    return [state, setStateAndSave] as const
  }
)

export const useLocalStore = createHook(localStorage)
export const useSessionStore = createHook(sessionStorage)
export const useQueryParamStore = createHook(queryParamStorage)
