import { result } from '.'

type Ok<T> = {
  type: 'ok'
  val: T
}
export const ok = <T>(val: T): Ok<T> => ({ type: 'ok', val })
type Err<T> = {
  type: 'err'
  err: T
}
export const err = <T>(err: T): Err<T> => ({ type: 'err', err })

export type Result<TOk, TErr> = Ok<TOk> | Err<TErr>

export const isOk = <TOk, TErr>(r: result.Result<TOk, TErr>): boolean => {
  switch (r.type) {
    case 'ok':
      return true
    default:
      return false
  }
}

export const getValue = <TOk, TErr>(r: result.Result<TOk, TErr>): TOk => {
  if (r.type === 'ok') {
    return r.val
  }

  throw new Error(`couldn't get value as type is error: ${r.err}`)
}

export const tap = <TOk, TErr>(
  r: result.Result<TOk, TErr>,
  okFunc: (okRes: TOk) => void,
  errFunc: (errRes: TErr) => void = (err) => {
    console.log("default tap catch of error, note tap doesn't break chain")
  }
): result.Result<TOk, TErr> => {
  switch (r.type) {
    case 'ok':
      okFunc(r.val)
      break
    case 'err':
      errFunc(r.err)
      break
  }

  return r
}

export const getError = <TOk, TErr = string>(
  r: result.Result<TOk, TErr>
): TErr => {
  if (r.type === 'err') {
    return r.err
  }

  throw new Error(`couldn't get value as type is ok: ${r.val}`)
}