# Markus Maiwald (Architect) | Voxis Forge (AI)
# Rumpk Phase 11: The Sovereign Filesystem (SFS)
# Simple Flat System (Contiguous, Directory-based, No Inodes)

# import ../ion # Removing to avoid cycle and ambiguity
# import ../kernel # Removing to avoid cycle

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

# =========================================================
# SFS Definitions
# =========================================================

const SFS_MAGIC = 0x31534653'u32 # "SFS1" in Little Endian (S=53, F=46, S=53, 1=31 -> 31 53 46 53? No, S is lowest addr)
 # "SFS1" as string: bufs[0]=S, buf[1]=F...
 # u32 representation depends on Endianness.
 # On Little Endian (RISC-V):
 # 0x31534653 -> LSB is 0x53 (S). MSB is 0x31 (1).
 # So "SFS1" in memory.

type
  Superblock* = object
    magic*: uint32
    disk_size*: uint32 # in sectors? or bytes? Nipbox wrote u64 bytes. Let's use sectors for kernel simplicity?
 # Stack layout alignment might be issue. Let's read raw bytes.

  DirEntry* = object
    filename*: array[32, char]
    start_sector*: uint32
    size_bytes*: uint32
    reserved*: array[24, byte] # Pad to 64 bytes? 32+4+4 = 40. 64-40=24.
                               # 512 / 64 = 8 entries per sector.

# =========================================================
# SFS State
# =========================================================

var sfs_mounted: bool = false
var io_buffer: array[512, byte] # Kernel IO Buffer for FS ops

# =========================================================
# SFS Driver
# =========================================================

# Import HAL block ops
proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.}
proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}

proc sfs_mount*() =
  kprintln("[SFS] Mounting System...")

  # 1. Read Sector 0 (Superblock)
  virtio_blk_read(0, addr io_buffer[0])

  # 2. Check Magic
  # "SFS1" -> 0x53, 0x46, 0x53, 0x31
  if io_buffer[0] == 0x53 and io_buffer[1] == 0x46 and
     io_buffer[2] == 0x53 and io_buffer[3] == 0x31:
    kprintln("[SFS] Mount SUCCESS. Magic: SFS1")
    sfs_mounted = true
  else:
    kprint("[SFS] Mount FAILED. Invalid Magic. Found: ")
    kprint_hex(cast[uint64](io_buffer[0]))
    kprint(" ")
    kprint_hex(cast[uint64](io_buffer[1]))
    kprint(" ")
    kprint_hex(cast[uint64](io_buffer[2]))
    kprintln("")

proc sfs_list*() =
  if not sfs_mounted:
    kprintln("[SFS] Error: Not mounted.")
    return

  # Read Sector 1 (Directory Table)
  virtio_blk_read(1, addr io_buffer[0])

  kprintln("[SFS] Files:")
  # Parse Entries (assuming 64 bytes stride for now if nipbox holds it)
  # Actually nipbox `mkfs` just zeroed it.

  var found = false
  var offset = 0
  while offset < 512:
    if io_buffer[offset] != 0:
      # Found entry
      var name: string = ""
      for i in 0..31:
        let c = char(io_buffer[offset+i])
        if c == '\0': break
        name.add(c)

      kprint("  - ")
      kprintln(cstring(name))
      found = true

    offset += 64

  if not found:
    kprintln("  (Empty)")

proc sfs_write_file*(name: cstring, data: cstring, data_len: int) =
  if not sfs_mounted:
    kprintln("[SFS] Write Error: Not mounted.")
    return

  # 1. Read Directory Table (Sector 1)
  virtio_blk_read(1, addr io_buffer[0])

  var free_slot_offset = -1
  var found_file_offset = -1
  var max_sector: uint32 = 1

  var offset = 0
  while offset < 512:
    if io_buffer[offset] != 0:
      var entry_name: string = ""
      for i in 0..31:
        if io_buffer[offset+i] == 0: break
        entry_name.add(char(io_buffer[offset+i]))

      if entry_name == $name:
        found_file_offset = offset

      var s_sect: uint32 = uint32(io_buffer[offset+32]) or
                           (uint32(io_buffer[offset+33]) shl 8) or
                           (uint32(io_buffer[offset+34]) shl 16) or
                           (uint32(io_buffer[offset+35]) shl 24)
      if s_sect > max_sector: max_sector = s_sect
    elif free_slot_offset == -1:
      free_slot_offset = offset

    offset += 64

  # 2. Determine Target Sector
  var target_sector: uint32 = 0
  var target_offset = 0

  if found_file_offset != -1:
    kprintln("[SFS] Overwriting existing file...")
    target_offset = found_file_offset
    target_sector = uint32(io_buffer[target_offset+32]) or
                    (uint32(io_buffer[target_offset+33]) shl 8) or
                    (uint32(io_buffer[target_offset+34]) shl 16) or
                    (uint32(io_buffer[target_offset+35]) shl 24)
  elif free_slot_offset != -1:
    kprintln("[SFS] Creating new file...")
    target_offset = free_slot_offset
    target_sector = max_sector + 1
  else:
    kprintln("[SFS] Error: Directory Full.")
    return

  # 3. Write Data
  kprint("[SFS] Writing to Sector: ")
  kprint_hex(uint64(target_sector))
  kprintln("")

  var data_buf: array[512, byte]
  for i in 0..511: data_buf[i] = 0
  for i in 0 ..< data_len:
    if i < 512: data_buf[i] = byte(data[i])

  virtio_blk_write(uint64(target_sector), addr data_buf[0])

  # 4. Update Directory Entry
  var n_str = $name
  for i in 0..31:
    if i < n_str.len: io_buffer[target_offset+i] = byte(n_str[i])
    else: io_buffer[target_offset+i] = 0

  io_buffer[target_offset+32] = byte(target_sector and 0xFF)
  io_buffer[target_offset+33] = byte((target_sector shr 8) and 0xFF)
  io_buffer[target_offset+34] = byte((target_sector shr 16) and 0xFF)
  io_buffer[target_offset+35] = byte((target_sector shr 24) and 0xFF)

  var sz = uint32(data_len)
  io_buffer[target_offset+36] = byte(sz and 0xFF)
  io_buffer[target_offset+37] = byte((sz shr 8) and 0xFF)
  io_buffer[target_offset+38] = byte((sz shr 16) and 0xFF)
  io_buffer[target_offset+39] = byte((sz shr 24) and 0xFF)

  # 5. Write Directory Table Back
  virtio_blk_write(1, addr io_buffer[0])
  kprintln("[SFS] Write Complete.")

