# 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: LittleFS Bridge
##
## Nim FFI wrapper for the Zig-side LittleFS HAL (littlefs_hal.zig).
## Provides the API that VFS delegates to for /nexus mount point.
##
## All calls cross the Nim→Zig→C boundary:
##   Nim (this file) → Zig (littlefs_hal.zig) → C (lfs.c) → VirtIO-Block

# --- FFI imports from littlefs_hal.zig (exported as C ABI) ---
proc nexus_lfs_format(): int32 {.importc, cdecl.}
proc nexus_lfs_mount(): int32 {.importc, cdecl.}
proc nexus_lfs_unmount(): int32 {.importc, cdecl.}
proc nexus_lfs_open(path: cstring, flags: int32): int32 {.importc, cdecl.}
proc nexus_lfs_read(handle: int32, buf: pointer, size: uint32): int32 {.importc, cdecl.}
proc nexus_lfs_write(handle: int32, buf: pointer, size: uint32): int32 {.importc, cdecl.}
proc nexus_lfs_close(handle: int32): int32 {.importc, cdecl.}
proc nexus_lfs_seek(handle: int32, off: int32, whence: int32): int32 {.importc, cdecl.}
proc nexus_lfs_size(handle: int32): int32 {.importc, cdecl.}
proc nexus_lfs_remove(path: cstring): int32 {.importc, cdecl.}
proc nexus_lfs_mkdir(path: cstring): int32 {.importc, cdecl.}
proc nexus_lfs_is_mounted(): int32 {.importc, cdecl.}

# --- LFS open flags (match lfs.h) ---
const
  LFS_O_RDONLY* = 1'i32
  LFS_O_WRONLY* = 2'i32
  LFS_O_RDWR*   = 3'i32
  LFS_O_CREAT*  = 0x0100'i32
  LFS_O_EXCL*   = 0x0200'i32
  LFS_O_TRUNC*  = 0x0400'i32
  LFS_O_APPEND* = 0x0800'i32

# --- LFS seek flags ---
const
  LFS_SEEK_SET* = 0'i32
  LFS_SEEK_CUR* = 1'i32
  LFS_SEEK_END* = 2'i32

# --- Public API for VFS ---

proc lfs_mount_fs*(): bool =
  ## Mount the LittleFS filesystem. Auto-formats on first boot.
  return nexus_lfs_mount() == 0

proc lfs_unmount_fs*(): bool =
  return nexus_lfs_unmount() == 0

proc lfs_format_fs*(): bool =
  return nexus_lfs_format() == 0

proc lfs_is_mounted*(): bool =
  return nexus_lfs_is_mounted() != 0

proc lfs_open_file*(path: cstring, flags: int32): int32 =
  ## Open a file. Returns handle >= 0 on success, < 0 on error.
  return nexus_lfs_open(path, flags)

proc lfs_read_file*(handle: int32, buf: pointer, size: uint32): int32 =
  ## Read from file. Returns bytes read or negative error.
  return nexus_lfs_read(handle, buf, size)

proc lfs_write_file*(handle: int32, buf: pointer, size: uint32): int32 =
  ## Write to file. Returns bytes written or negative error.
  return nexus_lfs_write(handle, buf, size)

proc lfs_close_file*(handle: int32): int32 =
  return nexus_lfs_close(handle)

proc lfs_seek_file*(handle: int32, off: int32, whence: int32): int32 =
  return nexus_lfs_seek(handle, off, whence)

proc lfs_file_size*(handle: int32): int32 =
  return nexus_lfs_size(handle)

proc lfs_remove_path*(path: cstring): int32 =
  return nexus_lfs_remove(path)

proc lfs_mkdir_path*(path: cstring): int32 =
  return nexus_lfs_mkdir(path)

# --- Convenience: VFS-compatible read/write (path-based, like SFS) ---

proc lfs_vfs_read*(path: cstring, buf: pointer, max_len: int): int =
  ## Read entire file into buffer. Returns bytes read or -1.
  let h = nexus_lfs_open(path, LFS_O_RDONLY)
  if h < 0: return -1
  let n = nexus_lfs_read(h, buf, uint32(max_len))
  discard nexus_lfs_close(h)
  if n < 0: return -1
  return int(n)

proc lfs_vfs_write*(path: cstring, buf: pointer, len: int) =
  ## Write buffer to file (create/truncate).
  let h = nexus_lfs_open(path, LFS_O_WRONLY or LFS_O_CREAT or LFS_O_TRUNC)
  if h < 0: return
  discard nexus_lfs_write(h, buf, uint32(len))
  discard nexus_lfs_close(h)

proc lfs_vfs_read_at*(path: cstring, buf: pointer, count: uint64,
                       offset: uint64): int64 =
  ## Read `count` bytes starting at `offset`. Returns bytes read.
  let h = nexus_lfs_open(path, LFS_O_RDONLY)
  if h < 0: return -1
  if offset > 0:
    discard nexus_lfs_seek(h, int32(offset), LFS_SEEK_SET)
  let n = nexus_lfs_read(h, buf, uint32(count))
  discard nexus_lfs_close(h)
  if n < 0: return -1
  return int64(n)

proc lfs_vfs_write_at*(path: cstring, buf: pointer, count: uint64,
                        offset: uint64): int64 =
  ## Write `count` bytes at `offset`. Returns bytes written.
  let flags = LFS_O_WRONLY or LFS_O_CREAT
  let h = nexus_lfs_open(path, flags)
  if h < 0: return -1
  if offset > 0:
    discard nexus_lfs_seek(h, int32(offset), LFS_SEEK_SET)
  let n = nexus_lfs_write(h, buf, uint32(count))
  discard nexus_lfs_close(h)
  if n < 0: return -1
  return int64(n)
