export interface StorageKey<T> extends String {};

function useWebStorage(storage: Storage) {
  function get<T, U>(key: StorageKey<T>, default_?: U | undefined): T | U {
    const value = storage.getItem(key as string);
    if(value == null) {
      if(default_ === undefined) {
        throw new RangeError(`Key "${key}" not found`);
      }
      return default_;
    }
    return JSON.parse(value) as T;
  }

  function has<T>(key: StorageKey<T>) {
    return storage.getItem(key as string) != null;
  }

  function set<T>(key: StorageKey<T>, value: T) {
    storage.setItem(key as string, JSON.stringify(value));
  }

  function delete_<T>(key: StorageKey<T>) {
    storage.removeItem(key as string);
  }

  function clear() {
    storage.clear();
  }

  return { get, has, set, delete: delete_, clear };
}

export function useSessionStorage() {
  return useWebStorage(globalThis.sessionStorage);
}

export function useLocalStorage() {
  return useWebStorage(globalThis.localStorage);
}

export type WebStorage = ReturnType<typeof useWebStorage>;
