# nimpak/utils/resultutils.nim
# Shared Result utilities to avoid circular imports

import std/options

type
  Result*[T, E] = object
    case isOk*: bool
    of true:
      value*: T
    of false:
      error*: E

# Result construction functions
proc ok*[T](value: T): Result[T, string] =
  Result[T, string](isOk: true, value: value)

proc err*[T](error: string): Result[T, string] =
  Result[T, string](isOk: false, error: error)

# Generic versions for specific error types
proc okResult*[T, E](value: T): Result[T, E] =
  Result[T, E](isOk: true, value: value)

proc errResult*[T, E](error: E): Result[T, E] =
  Result[T, E](isOk: false, error: error)

# Result utility functions
proc isErr*[T, E](r: Result[T, E]): bool =
  not r.isOk

proc get*[T, E](r: Result[T, E]): T =
  ## Get the value from a Result, raising an exception if it's an error
  if r.isOk:
    return r.value
  else:
    raise newException(ValueError, "Cannot get value from error result: " & $r.error)

proc error*[T, E](r: Result[T, E]): E =
  if not r.isOk:
    r.error
  else:
    raise newException(ValueError, "Cannot get error from ok result")

# Additional utility functions for Result handling
proc mapResult*[T, E, U](r: Result[T, E], f: proc(x: T): U): Result[U, E] =
  ## Map a function over the success value of a Result
  if r.isOk:
    ok[U, E](f(r.get))
  else:
    err[U, E](r.error)

proc flatMapResult*[T, E, U](r: Result[T, E], f: proc(x: T): Result[U, E]): Result[U, E] =
  ## Flat map a function over the success value of a Result
  if r.isOk:
    f(r.get)
  else:
    err[U, E](r.error)

proc orElse*[T, E](r: Result[T, E], default: T): T =
  ## Get the value or return a default
  if r.isOk:
    r.get
  else:
    default