///|
priv suberror RealpathError {
  RealpathError(String)
}

///|
async fn canonicalize(
  path : String,
  canonicalize_existing : Bool,
) -> String raise RealpathError {
  @fs.realpath(path) catch {
    error => {
      let description = if canonicalize_existing {
        "cannot canonicalize existing path"
      } else {
        "cannot canonicalize path"
      }
      raise RealpathError("\{description} '\{path}': \{error}")
    }
  }
}

///|
async fn main {
  let args = @env.args()[1:]
  let parsed = @cli.parse(args, [
    @cli.flag("canonicalize-existing", short='e'),
    @cli.flag("zero", short='z'),
    @cli.flag("help"),
    @cli.flag("version"),
  ]) catch {
    @cli.CliError(option~, message~, ..) => {
      @stdio.stderr.write("realpath: \{message}: '\{option}'\n")
      @sys.exit(2)
      return
    }
  }
  if parsed.contains("help") {
    let message =
      #|Usage: realpath [-e] [-z] NAME...
      #|  -e, --canonicalize-existing  require every path component to exist
      #|  -z, --zero                   separate output with NUL bytes
    @stdio.stdout.write(message)
    return
  }
  if parsed.contains("version") {
    @stdio.stdout.write("realpath (moonbit cmd) \{command_version}\n")
    return
  }
  if parsed.operands.is_empty() {
    @stdio.stderr.write("realpath: missing operand\n")
    @sys.exit(1)
    return
  }
  let canonicalize_existing = parsed.contains("canonicalize-existing")
  let separator = if parsed.contains("zero") { "\u0000" } else { "\n" }
  let mut failed = false
  for path in parsed.operands {
    let canonical = canonicalize(path, canonicalize_existing) catch {
      RealpathError(message) => {
        @stdio.stderr.write("realpath: \{message}\n")
        failed = true
        continue
      }
    }
    @stdio.stdout.write(canonical + separator)
  }
  if failed {
    @sys.exit(1)
  }
}