import React from "react";
import { atomFamily, useRecoilState } from "recoil";

const getFromLocalStorage = (key) => {
  const item = window.localStorage.getItem(key);
  if (item === undefined) {
    return undefined;
  }
  return JSON.parse(item);
};

const localStorageFamily = atomFamily({
  key: "localstorage",
  default: (key) => [false, getFromLocalStorage(key)],
});

const useLocalStorage = (key, initialValue) => {
  const [[loaded, storedValue], setStoredValue] = useRecoilState(
    localStorageFamily(key)
  );

  React.useEffect(() => {
    if (!loaded) {
      try {
        // Get from local storage by key
        const item = window.localStorage.getItem(key);

        if (item === undefined) {
          // If missing we add it
          window.localStorage.setItem(key, JSON.stringify(initialValue));
          setStoredValue([true, initialValue]);
        }
        setStoredValue([true, JSON.parse(item)]);
      } catch (error) {
        // If error also return initialValue
        console.log(error);
        setStoredValue([true, initialValue]);
      }
    }
  }, [initialValue, key, loaded, setStoredValue]);

  // Return a wrapped version of useState's setter function that ...
  // ... persists the new value to localStorage.
  const setValue = React.useCallback(
    (value) => {
      try {
        // Allow value to be a function so we have same API as useState
        const valueToStore =
          value instanceof Function ? value(storedValue) : value;

        // Save state
        setStoredValue([true, valueToStore]);

        // Save to local storage
        window.localStorage.setItem(key, JSON.stringify(valueToStore));
      } catch (error) {
        // A more advanced implementation would handle the error case
        console.log(error);
      }
    },
    [key, setStoredValue, storedValue]
  );

  // React on other tab modifications
  React.useEffect(() => {
    const localStorageChanged = (e) => {
      if (e.key === key) {
        setStoredValue([true, JSON.parse(e.newValue)]);
      }
    };
    window.addEventListener("storage", localStorageChanged);
    return () => {
      window.removeEventListener("storage", localStorageChanged);
    };
  }, [key, setStoredValue]);

  return [storedValue === undefined ? initialValue : storedValue, setValue];
};

export default useLocalStorage;
