# Markus Maiwald (Architect) | Voxis Forge (AI)
# libc.nim - Sovereign Libc for Nexus
# (C) 2026 Markus Maiwald

import ion_client


proc memcpy*(dest, src: pointer, n: uint64): pointer {.importc, cdecl.}
template copyMem*(dest, src: pointer, n: uint64) = discard memcpy(dest, src, n)



proc syscall*(nr: int, a0: uint64 = 0, a1: uint64 = 0, a2: uint64 = 0): int =
  var res: int
  let n = cast[uint64](nr)
  let v0 = a0
  let v1 = a1
  let v2 = a2
  {.emit: """
    register unsigned long a7 __asm__("a7") = `n`;
    register unsigned long a0_ __asm__("a0") = `v0`;
    register unsigned long a1_ __asm__("a1") = `v1`;
    register unsigned long a2_ __asm__("a2") = `v2`;
    __asm__ volatile("ecall" : "+r"(a0_) : "r"(a7), "r"(a1_), "r"(a2_) : "memory");
    `res` = (int)a0_;
  """.}
  return res

# --- LIBC IO SHIMS ---

proc write*(fd: int, buf: pointer, count: uint64): int {.exportc, cdecl.} =
  # Always use syscall, even for stdout/stderr. Kernel handles it.
  return int(syscall(0x204, uint64(fd), cast[uint64](buf), count))

proc read*(fd: int, buf: pointer, count: uint64): int {.exportc, cdecl.} =
  return int(syscall(0x203, uint64(fd), cast[uint64](buf), count))

proc open*(path: cstring, flags: int = 0): int {.exportc, cdecl.} =
  return int(syscall(0x200, cast[uint64](path), uint64(flags)))

proc close*(fd: int): int {.exportc, cdecl.} =
  return int(syscall(0x201, uint64(fd)))

proc print*(s: string) =
  if s.len > 0: discard write(1, unsafeAddr s[0], uint64(s.len))

proc readdir*(buf: pointer, max_len: uint64): int {.exportc, cdecl.} =
  return int(syscall(0x202, cast[uint64](buf), max_len))

proc exit*(status: int) {.exportc, cdecl.} =
  discard syscall(0x01, uint64(status))
  while true: discard

proc yield_fiber*() {.exportc: "yield", cdecl.} =
  discard syscall(0x100, 0)

proc pledge*(promises: uint64): int {.exportc, cdecl.} =
  return int(syscall(0x101, promises))

proc spawn*(entry: pointer, arg: uint64): int {.exportc, cdecl.} =
  return int(syscall(0x500, cast[uint64](entry), arg))

proc join*(fid: int): int {.exportc, cdecl.} =
  return int(syscall(0x501, uint64(fid)))

proc upgrade*(id: int, path: cstring): int {.exportc, cdecl.} =
  return -1 # Not implemented yet

proc get_vfs_listing*(): seq[string] =
  var buf: array[4096, char]
  let n = readdir(addr buf[0], 4096)
  if n <= 0: return @[]
  
  result = @[]
  var current = ""
  for i in 0..<n:
    if buf[i] == '\n':
      if current.len > 0:
        result.add(current)
        current = ""
    else:
      current.add(buf[i])
  if current.len > 0: result.add(current)

# Surface API (Glyph)
proc sys_surface_create*(width, height: int): int {.exportc, cdecl.} =
  return int(syscall(0x300, uint64(width), uint64(height)))

proc sys_surface_flip*(surf_id: int = 0) {.exportc, cdecl.} =
  discard syscall(0x301, uint64(surf_id))

proc sys_surface_get_ptr*(surf_id: int): pointer {.exportc, cdecl.} =
  return cast[pointer](syscall(0x302, uint64(surf_id)))

# Stubs for Glyph/NipBox compatibility
proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} = return -1
proc connect*(fd: int, addr_ptr: pointer, len: int): int {.exportc, cdecl.} = return -1
proc send*(fd: int, buf: pointer, count: uint64, flags: int): int {.exportc, cdecl.} = return 0
proc recv*(fd: int, buf: pointer, count: uint64, flags: int): int {.exportc, cdecl.} = return 0
proc lseek*(fd: int, offset: int, whence: int): int {.exportc, cdecl.} = return 0
proc fstat*(fd: int, buf: pointer): int {.exportc, cdecl.} = return 0
proc stat*(path: cstring, buf: pointer): int {.exportc, cdecl.} = return 0

proc membrane_init*() {.importc, cdecl.}
proc pump_membrane_stack*() {.importc, cdecl.}
