# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# Rumpk L1: Sovereign VFS (Indexing TarFS)

{.push stackTrace: off, lineTrace: off.}

import std/tables

# Kernel Imports
proc kprint(s: cstring) {.importc, cdecl.}
proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint_hex(n: uint64) {.importc, cdecl.}

type
  TarHeader* = array[512, byte]

  FileEntry = object
    offset*: uint64
    size*: uint64
    is_sfs*: bool

  FileHandle = object
    path*: string
    offset*: uint64
    is_sfs*: bool
    is_ram*: bool

  VFSInitRD* = object
    start_addr*: uint64
    end_addr*: uint64
    index*: Table[string, FileEntry]
    ram_data*: Table[string, seq[byte]]
    fds*: Table[int, FileHandle]
    next_fd*: int

var vfs*: VFSInitRD

proc vfs_init*(s: pointer, e: pointer) =
  vfs.start_addr = cast[uint64](s)
  vfs.end_addr = cast[uint64](e)
  vfs.index = initTable[string, FileEntry]()
  vfs.ram_data = initTable[string, seq[byte]]()
  vfs.fds = initTable[int, FileHandle]()
  vfs.next_fd = 3

  # kprint("[VFS] InitRD Start: "); kprint_hex(vfs.start_addr); kprintln("")
  # kprint("[VFS] InitRD End:   "); kprint_hex(vfs.end_addr); kprintln("")

  var p = vfs.start_addr
  while p < vfs.end_addr:
    let h = cast[ptr TarHeader](p)
    if h[][0] == byte(0): break

    # kprint("[VFS] Raw Header: ")
    # for i in 0..15:
    #   kprint_hex(uint64(h[][i]))
    #   kprint(" ")
    # kprintln("")

    # Extract and normalize name directly from header
    var name_len = 0
    while name_len < 100 and h[][name_len] != 0:
      inc name_len

    var start_idx = 0
    if name_len >= 2 and h[][0] == byte('.') and h[][1] == byte('/'):
      start_idx = 2
    elif name_len >= 1 and h[][0] == byte('/'):
      start_idx = 1

    let clean_len = name_len - start_idx
    var clean = ""
    if clean_len > 0:
      clean = newString(clean_len)
      # Copy directly from header memory
      for i in 0..<clean_len:
        clean[i] = char(h[][start_idx + i])

    if clean.len > 0:
      # Extract size (octal string)
      var size: uint64 = 0
      for i in 124..134:
        let b = h[][i]
        if b >= byte('0') and b <= byte('7'):
          size = (size shl 3) or uint64(b - byte('0'))

      vfs.index[clean] = FileEntry(offset: p + 512'u64, size: size, is_sfs: false)

      # Move to next header
      let padded_size = (size + 511'u64) and not 511'u64
      p += 512'u64 + padded_size
    else:
      p += 512'u64 # Skip invalid/empty

proc vfs_open*(path: string, flags: int32 = 0): int =
  var start_idx = 0
  if path.len > 0 and path[0] == '/':
    start_idx = 1

  let clean_len = path.len - start_idx
  var clean = ""
  if clean_len > 0:
    clean = newString(clean_len)
    for i in 0..<clean_len:
      clean[i] = path[start_idx + i]

  # 1. Check RamFS
  if vfs.ram_data.hasKey(clean):
    let fd = vfs.next_fd
    vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: false, is_ram: true)
    vfs.next_fd += 1
    return fd

  # 2. Check TarFS
  if vfs.index.hasKey(clean):
    let entry = vfs.index[clean]
    let fd = vfs.next_fd
    vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: entry.is_sfs,
        is_ram: false)
    vfs.next_fd += 1
    return fd

  # 3. Create if O_CREAT (bit 6 in POSIX)
  if (flags and 64) != 0:
    vfs.ram_data[clean] = @[]
    let fd = vfs.next_fd
    vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: false, is_ram: true)
    vfs.next_fd += 1
    return fd

  return -1

proc vfs_read_file*(path: string): string =
  var start_idx = 0
  if path.len > 0 and path[0] == '/':
    start_idx = 1

  let clean_len = path.len - start_idx
  var clean = ""
  if clean_len > 0:
    clean = newString(clean_len)
    for i in 0..<clean_len:
      clean[i] = path[start_idx + i]

  if vfs.ram_data.hasKey(clean):
    let data = vfs.ram_data[clean]
    if data.len == 0: return ""
    var s = newString(data.len)
    copyMem(addr s[0], unsafeAddr data[0], data.len)
    return s

  if vfs.index.hasKey(clean):
    let entry = vfs.index[clean]
    if entry.is_sfs: return ""
    var s = newString(int(entry.size))
    if entry.size > 0:
      copyMem(addr s[0], cast[pointer](entry.offset), int(entry.size))
    return s
  return ""

proc ion_vfs_open*(path: cstring, flags: int32): int32 {.exportc, cdecl.} =
  return int32(vfs_open($path, flags))

proc sfs_write_file(name: cstring, data: cstring, data_len: int) {.importc, cdecl.}
proc sfs_read_file(name: cstring, dest: pointer, max_len: int): int {.importc, cdecl.}

proc ion_vfs_read*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
  let fd_int = int(fd)
  if not vfs.fds.hasKey(fd_int): return -1
  let fh = addr vfs.fds[fd_int]

  if fh.is_sfs:
    # Read to temp buffer to handle offset/slicing
    var temp_buf: array[512, byte]
    let total_n = sfs_read_file(cstring(fh.path), addr temp_buf[0], 512)
    if total_n < 0: return -1

    if fh.offset >= uint64(total_n): return 0
    let available = uint64(total_n) - fh.offset
    let actual = min(count, available)

    if actual > 0:
      copyMem(buf, addr temp_buf[int(fh.offset)], int(actual))
      fh.offset += actual
    return int64(actual)

  # 1. RamFS Read
  if fh.is_ram:
    if not vfs.ram_data.hasKey(fh.path): return 0
    let data = addr vfs.ram_data[fh.path]
    if fh.offset >= uint64(data[].len): return 0
    let available = uint64(data[].len) - fh.offset
    let actual_count = min(count, available)
    if actual_count > 0:
      copyMem(buf, addr data[][int(fh.offset)], int(actual_count))
      fh.offset += actual_count
    return int64(actual_count)

  # 2. Tar Read
  let entry = vfs.index[fh.path]
  var actual_count = uint64(count)

  if fh.offset >= entry.size: return 0
  if fh.offset + uint64(count) > entry.size:
    actual_count = entry.size - fh.offset

  copyMem(buf, cast[pointer](entry.offset + fh.offset), int(actual_count))
  fh.offset += actual_count

  return int64(actual_count)

proc ion_vfs_close*(fd: int32): int32 {.exportc, cdecl.} =
  let fd_int = int(fd)
  if vfs.fds.hasKey(fd_int):
    vfs.fds.del(fd_int)
    return 0
  return -1

proc ion_vfs_write*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
  let fd_int = int(fd)
  if not vfs.fds.hasKey(fd_int): return -1
  let fh = addr vfs.fds[fd_int]

  if fh.is_sfs:
    sfs_write_file(cstring(fh.path), cast[cstring](buf), int(count))
    return int64(count)

  # 1. Promote to RamFS if on TarFS (CoW)
  if not fh.is_ram:
    if vfs.index.hasKey(fh.path):
      let entry = vfs.index[fh.path]
      var content = newSeq[byte](int(entry.size))
      if entry.size > 0:
        copyMem(addr content[0], cast[pointer](entry.offset), int(entry.size))
      vfs.ram_data[fh.path] = content
      fh.is_ram = true
      # fh.offset preserved
    else:
      # Should not happen if open was successful, but for safety:
      vfs.ram_data[fh.path] = @[]
      fh.is_ram = true

  # 2. RamFS Write
  let data = addr vfs.ram_data[fh.path]
  let min_size = int(fh.offset + count)
  if data[].len < min_size:
    data[].setLen(min_size)

  copyMem(addr data[][int(fh.offset)], buf, int(count))
  fh.offset += count
  return int64(count)

proc ion_vfs_list*(buf: pointer, max_len: uint64): int64 {.exportc, cdecl.} =
  var s = ""
  # Unique names from both
  var names = initTable[string, bool]()
  for name, _ in vfs.index: names[name] = true
  for name, _ in vfs.ram_data: names[name] = true

  for name, _ in names: s.add(name & "\n")
  let n = min(s.len, int(max_len))
  if n > 0: copyMem(buf, addr s[0], n)
  return int64(n)

proc vfs_register_sfs*(name: string, size: uint64) {.exportc, cdecl.} =
  vfs.index[name] = FileEntry(offset: 0, size: size, is_sfs: true)

{.pop.}
