# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.

## Rumpk Layer 1: Sovereign File System (SFS)
##
## Freestanding implementation (No OS module dependencies).
## Uses fixed-size buffers and raw blocks for persistence.

import ring, fiber # For yield

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

const SFS_MAGIC* = 0x31534653'u32
const
  SEC_SB = 0
  SEC_BAM = 1
  SEC_DIR = 2
  CHUNK_SIZE = 508
  EOF_MARKER = 0xFFFFFFFF'u32

var sfs_mounted: bool = false
var io_buffer: array[512, byte]

proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.}
proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}

proc sfs_alloc_sector(): uint32 =
  virtio_blk_read(SEC_BAM, addr io_buffer[0])
  for i in 0..<512:
    if io_buffer[i] != 0xFF:
      for b in 0..7:
        if (io_buffer[i] and byte(1 shl b)) == 0:
          let sec = uint32(i * 8 + b)
          io_buffer[i] = io_buffer[i] or byte(1 shl b)
          virtio_blk_write(SEC_BAM, addr io_buffer[0])
          return sec
  return 0

proc sfs_mount*() =
  virtio_blk_read(SEC_SB, addr io_buffer[0])
  if io_buffer[0] == byte('S') and io_buffer[1] == byte('F') and
     io_buffer[2] == byte('S') and io_buffer[3] == byte('2'):
    sfs_mounted = true
  else:
    sfs_mounted = false

proc sfs_streq(s1, s2: cstring): bool =
  let p1 = cast[ptr UncheckedArray[char]](s1)
  let p2 = cast[ptr UncheckedArray[char]](s2)
  var i = 0
  while true:
    if p1[i] != p2[i]: return false
    if p1[i] == '\0': return true
    i += 1

proc sfs_write_file*(name: cstring, data: pointer, data_len: int) {.exportc, cdecl.} =
  if not sfs_mounted: return
  virtio_blk_read(SEC_DIR, addr io_buffer[0])
  var dir_offset = -1
  for offset in countup(0, 511, 64):
    if io_buffer[offset] != 0:
      if sfs_streq(name, cast[cstring](addr io_buffer[offset])):
        dir_offset = offset
        break
    elif dir_offset == -1: dir_offset = offset
  if dir_offset == -1: return

  var remaining = data_len
  var data_addr = cast[uint64](data)
  var current_sector = sfs_alloc_sector()
  if current_sector == 0: return
  let first_sector = current_sector

  while remaining > 0:
    var sector_buf: array[512, byte]
    let chunk = if remaining > CHUNK_SIZE: CHUNK_SIZE else: remaining
    copyMem(addr sector_buf[0], cast[pointer](data_addr), chunk)
    remaining -= chunk
    data_addr += uint64(chunk)

    var next_sector = EOF_MARKER
    if remaining > 0:
      next_sector = sfs_alloc_sector()
      if next_sector == 0: next_sector = EOF_MARKER
    
    # Write next pointer at end of block
    cast[ptr uint32](addr sector_buf[508])[] = next_sector
    virtio_blk_write(uint64(current_sector), addr sector_buf[0])
    current_sector = next_sector
    if current_sector == EOF_MARKER: break

  # Update Directory
  virtio_blk_read(SEC_DIR, addr io_buffer[0])
  let nm = cast[ptr UncheckedArray[char]](name)
  var i = 0
  while nm[i] != '\0' and i < 31:
    io_buffer[dir_offset + i] = byte(nm[i])
    i += 1
  io_buffer[dir_offset + i] = 0
  cast[ptr uint32](addr io_buffer[dir_offset + 32])[] = first_sector
  cast[ptr uint32](addr io_buffer[dir_offset + 36])[] = uint32(data_len)
  virtio_blk_write(SEC_DIR, addr io_buffer[0])

proc sfs_read_file*(name: cstring, dest: pointer, max_len: int): int {.exportc, cdecl.} =
  if not sfs_mounted: return -1
  virtio_blk_read(SEC_DIR, addr io_buffer[0])
  var start_sector = 0'u32
  var file_size = 0'u32
  var found = false
  for offset in countup(0, 511, 64):
    if io_buffer[offset] != 0:
      if sfs_streq(name, cast[cstring](addr io_buffer[offset])):
        start_sector = cast[ptr uint32](addr io_buffer[offset + 32])[]
        file_size = cast[ptr uint32](addr io_buffer[offset + 36])[]
        found = true
        break
  if not found: return -1

  var current_sector = start_sector
  var dest_addr = cast[uint64](dest)
  var remaining = if int(file_size) < max_len: int(file_size) else: max_len
  var total = 0
  while remaining > 0 and current_sector != EOF_MARKER:
     var sector_buf: array[512, byte]
     virtio_blk_read(uint64(current_sector), addr sector_buf[0])
     let chunk = if remaining < CHUNK_SIZE: remaining else: CHUNK_SIZE
     copyMem(cast[pointer](dest_addr), addr sector_buf[0], chunk)
     dest_addr += uint64(chunk)
     remaining -= chunk
     total += chunk
     current_sector = cast[ptr uint32](addr sector_buf[508])[]
  return total

proc sfs_get_files*(): cstring = return "boot.kdl\n" # Dummy
