# 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: ION Interface (The Sovereign Protocol)
##
## Defines the core communication protocol between Kernel and Userland.
## Implements the SysTable structure, packet types, and Sovereign Channels.
##
## SAFETY: Provides the ABI contract for lock-free communication.

# CRITICAL: Only import memory module for kernel builds
# Userspace builds (with -d:is_membrane) should NOT get the 2MB pool
when not defined(is_membrane):
  import ion/memory
  export memory

const
  PLEDGE_STDIO* = 0x0001'u64
  PLEDGE_RPATH* = 0x0002'u64
  PLEDGE_WPATH* = 0x0004'u64
  PLEDGE_INET* = 0x0008'u64
  PLEDGE_EXEC* = 0x0010'u64
  PLEDGE_ALL* = 0xFFFFFFFFFFFFFFFF'u64

type
  CmdType* = enum
    CMD_SYS_NOOP = 0
    CMD_SYS_EXIT = 1
    CMD_ION_STOP = 2
    CMD_ION_START = 3
    CMD_GPU_MATRIX = 0x100
    CMD_GPU_CLEAR = 0x101
    CMD_GET_GPU_STATUS = 0x102
    CMD_FS_OPEN = 0x200
    CMD_FS_READ = 0x201
    CMD_FS_READDIR = 0x202 
    CMD_FS_WRITE = 0x203
    CMD_FS_MOUNT = 0x204
    CMD_ION_FREE = 0x300
    CMD_SYS_EXEC = 0x400
    CMD_NET_TX = 0x500
    CMD_NET_RX = 0x501
    CMD_BLK_READ = 0x600
    CMD_BLK_WRITE = 0x601
    CMD_SPAWN_FIBER = 0x700

  CmdPacket* = object
    kind*: uint32
    reserved*: uint32
    arg*: uint64
    id*: array[16, byte]

  NetArgs* = object
    buf*: uint64
    len*: uint64

  BlkArgs* = object
    sector*: uint64
    buf*: uint64
    len*: uint64

  FileArgs* = object
    name*: uint64
    data*: uint64
    len*: uint64

  HAL_Ring*[T] = object
    head*: uint32
    tail*: uint32
    mask*: uint32
    data*: array[256, T]

  SovereignChannel*[T] = object
    ring*: ptr HAL_Ring[T]

  SysTable* = object
    magic*: uint32                                      # 0x4E585553
    reserved*: uint32                                   
    s_rx*: ptr HAL_Ring[IonPacket]
    s_tx*: ptr HAL_Ring[IonPacket]
    s_event*: ptr HAL_Ring[IonPacket]
    s_cmd*: ptr HAL_Ring[CmdPacket]
    s_input*: ptr HAL_Ring[IonPacket]
                                                        # Function Pointers
    fn_vfs_open*: proc(path: cstring, flags: int32): int32 {.cdecl.}
    fn_vfs_read*: proc(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
    fn_vfs_list*: proc(buf: pointer, max_len: uint64): int64 {.cdecl.}
    fn_vfs_write*: proc(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
    fn_vfs_close*: proc(fd: int32): int32 {.cdecl.}
    fn_log*: pointer
    fn_pledge*: proc(promises: uint64): int32 {.cdecl.}
    
    # Framebuffer
    fb_addr*: uint64
    fb_width*: uint32
    fb_height*: uint32
    fb_stride*: uint32
    fb_bpp*: uint32
    fn_yield*: proc() {.cdecl.}

    # Phase 35e: Crypto
    fn_siphash*: proc(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.cdecl.}
    fn_ed25519_verify*: proc(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.cdecl.}
    # SPEC-503: Monolith Key Derivation
    fn_blake3*: proc(data: pointer, len: uint64, out_hash: ptr array[32, byte]) {.cdecl.}

    # Phase 36.2: Network Membrane (The Veins)
    s_net_rx*: ptr HAL_Ring[IonPacket]  # Kernel Producer -> User Consumer
    s_net_tx*: ptr HAL_Ring[IonPacket]  # User Producer -> Kernel Consumer

    # Phase 36.3: Shared ION (16 bytes)
    fn_ion_alloc*: proc(out_id: ptr uint16): uint64 {.cdecl.}
    fn_ion_free*: proc(id: uint16) {.cdecl.}
    
    # Phase 36.4: I/O Multiplexing (8 bytes)
    fn_wait_multi*: proc(mask: uint64): int32 {.cdecl.}
    
    # Phase 36.5: Network Hardware Info (8 bytes)
    net_mac*: array[6, byte]
    reserved_mac*: array[2, byte]

include invariant

# --- Sovereign Logic ---

# HAL Imports
proc hal_channel_push*(ring: uint64, pkt: IonPacket): bool {.importc, cdecl.}
proc hal_channel_pop*(ring: uint64, out_pkt: ptr IonPacket): bool {.importc, cdecl.}
proc hal_cmd_push*(ring: uint64, pkt: CmdPacket): bool {.importc, cdecl.}
proc hal_cmd_pop*(ring: uint64, out_pkt: ptr CmdPacket): bool {.importc, cdecl.}

proc send*[T](c: var SovereignChannel[T], pkt: T): bool =
  if c.ring == nil: return false
  when T is IonPacket:
    return hal_channel_push(cast[uint64](c.ring), pkt)
  elif T is CmdPacket:
    return hal_cmd_push(cast[uint64](c.ring), pkt)
  else:
    return false

proc recv*[T](c: var SovereignChannel[T], out_pkt: var T): bool =
  if c.ring == nil: return false
  when T is IonPacket:
    return hal_channel_pop(cast[uint64](c.ring), addr out_pkt)
  elif T is CmdPacket:
    return hal_cmd_pop(cast[uint64](c.ring), addr out_pkt)

var chan_input*: SovereignChannel[IonPacket]
var chan_cmd*: SovereignChannel[CmdPacket]
var chan_rx*: SovereignChannel[IonPacket]
var chan_tx*: SovereignChannel[IonPacket]

var guest_input_hal: HAL_Ring[IonPacket]
var cmd_hal: HAL_Ring[CmdPacket]
var rx_hal: HAL_Ring[IonPacket]
var tx_hal: HAL_Ring[IonPacket]

# Phase 36.2: Network Channels
var chan_net_rx*: SovereignChannel[IonPacket]
var chan_net_tx*: SovereignChannel[IonPacket]
var chan_netswitch_rx*: SovereignChannel[IonPacket] # Internal: Driver -> NetSwitch
var net_rx_hal: HAL_Ring[IonPacket]
var net_tx_hal: HAL_Ring[IonPacket]
var netswitch_rx_hal: HAL_Ring[IonPacket]

proc ion_init_input*() {.exportc, cdecl.} =
  guest_input_hal.head = 0
  guest_input_hal.tail = 0
  guest_input_hal.mask = 255
  chan_input.ring = addr guest_input_hal

proc ion_init_network*() {.exportc, cdecl.} =
  # NOTE: This function is called early in kernel boot.
  # The actual ring memory will be allocated in SYSTABLE region by kmain.
  # We just initialize the local HAL rings here for internal kernel use.
  net_rx_hal.head = 0
  net_rx_hal.tail = 0
  net_rx_hal.mask = 255
  chan_net_rx.ring = addr net_rx_hal
  
  net_tx_hal.head = 0
  net_tx_hal.tail = 0
  net_tx_hal.mask = 255
  chan_net_tx.ring = addr net_tx_hal

  netswitch_rx_hal.head = 0
  netswitch_rx_hal.tail = 0
  netswitch_rx_hal.mask = 255
  chan_netswitch_rx.ring = addr netswitch_rx_hal
  
  # Initialize user slab
  ion_user_slab_init()

# Internal allocators removed - use shared/systable versions


# =========================================================
# SysTable-Compatible Wrappers for User Slab
# =========================================================
# These wrappers have the same signature as fn_ion_alloc/fn_ion_free
# but use the user slab instead of the kernel ION pool.

# Track allocated buffers by pseudo-ID (index in slab)
proc ion_user_alloc_systable*(out_id: ptr uint16): uint64 {.exportc, cdecl.} =
  ## SysTable-compatible allocator using user slab (via shared bitmap)
  return ion_alloc_shared(out_id)

proc ion_user_free_systable*(id: uint16) {.exportc, cdecl.} =
  ## SysTable-compatible free using user slab
  var pkt: IonPacket
  pkt.id = id
  pkt.data = cast[ptr UncheckedArray[byte]](1) # Dummy non-nil
  ion_free(pkt)

static: doAssert(sizeof(IonPacket) == 24, "IonPacket size mismatch!")
static: doAssert(sizeof(CmdPacket) == 32, "CmdPacket size mismatch!")
static: doAssert(sizeof(SysTable) == 208, "SysTable size mismatch! (Expected 208 after MAC+pad)")
