type Store = typeof localStorage | typeof sessionStorage

type SetTransform<T> = (args: T) => string
type GetTransform<T> = (args: null | string) => T

export function get(store: Store, name: string): string | null
export function get<T>(
  store: Store,
  name: string,
  transform: GetTransform<T>
): T
export function get(store, name, transform?) {
  const value = store.getItem(name)
  if (transform) {
    return transform(value)
  } else {
    return value
  }
}

export function set(store: Store, name: string, value: string): string
export function set<T>(
  store: Store,
  name: string,
  value: T,
  transform: SetTransform<T>
): string
export function set(store, name, value, transform?) {
  if (transform) {
    value = transform(value)
  }
  store.setItem(name, value)
  return value
}

export function getFactory(store: Store): (name: string) => string | null
export function getFactory<T>(
  store: Store,
  transform: GetTransform<T>
): (name: string | null) => T
export function getFactory<T>(store: Store, transform?: GetTransform<T>) {
  return (name: string | null) =>
    transform ? get(store, name, transform) : get(store, name)
}

export function setFactory(
  store: Store
): (name: string, value: string) => string
export function setFactory<T>(
  store: Store,
  transform: SetTransform<T>
): (name: string, value: T) => string
export function setFactory(store, transform?) {
  return (name: string, value) =>
    transform ? set(store, name, transform(value)) : set(store, name, value)
}

export function localGetFactory(): (name: string) => string | null
export function localGetFactory<T>(
  transform: GetTransform<T>
): (name: string | null) => T
export function localGetFactory(transform?) {
  return getFactory(localStorage, transform)
}

export function localSetFactory(): (name: string, value: string) => string
export function localSetFactory<T>(
  transform: SetTransform<T>
): (name: string, value: T) => string
export function localSetFactory(transform?) {
  return setFactory(localStorage, transform)
}
export function localDel(key) {
  localStorage.removeItem(key)
}

export function sessionGetFactory(): (name: string) => string | null
export function sessionGetFactory<T>(
  transform: GetTransform<T>
): (name: string | null) => T
export function sessionGetFactory(transform?) {
  return getFactory(sessionStorage, transform)
}

export function sessionSetFactory(): (name: string, value: string) => string
export function sessionSetFactory<T>(
  transform: SetTransform<T>
): (name: string, value: T) => string
export function sessionSetFactory(transform?) {
  return setFactory(sessionStorage, transform)
}

export function sessionDel(key) {
  sessionStorage.removeItem(key)
}

export const local = {
  get: localGetFactory(),
  set: localSetFactory(),
  del: localDel
}

export const session = {
  get: sessionGetFactory(),
  set: sessionSetFactory(),
  del: sessionDel
}
