# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# Rumpk Layer 1: The Logic Core (Autonomous Immune System)

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

import fiber
import ion
import loader

var ion_paused*: bool = false
var pause_start*: uint64 = 0
var matrix_enabled*: bool = false


# =========================================================
# Fiber Management (Forward Declared)
# =========================================================

var fiber_ion: FiberObject
var fiber_nexshell: FiberObject
var fiber_ui: FiberObject
var fiber_subject: FiberObject
var fiber_watchdog: FiberObject

var subject_loading_path: string = "bin/nipbox"

proc subject_fiber_entry() {.cdecl.} =
  ## The Sovereign Container for Userland Consciousness.
  ## This loop persists across program reloads.
  while true:
    let entry = kload(subject_loading_path)
    if entry != 0:
      kprintln("[Subject] Consciousness Transferred.")
      rumpk_enter_userland(entry)

    kprintln("[Subject] Failed to load or returned. Pausing for Rebirth.")
    fiber_yield()

# --- STACK ALLOCATIONS ---
var stack_ion {.align: 16.}: array[4096, uint8]
var stack_nexshell {.align: 16.}: array[4096, uint8]
var stack_ui {.align: 16.}: array[32768, uint8]
var stack_subject {.align: 16.}: array[32768, uint8]
var stack_watchdog {.align: 16.}: array[4096, uint8]

# Exports for Zig NPLs
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
proc write*(fd: cint, p: pointer, len: csize_t): csize_t {.exportc, cdecl.} =
  console_write(p, len)
  return len

# Utility for Logic Core
proc kwrite*(p: pointer, len: csize_t) {.exportc, cdecl.} =
  if p != nil and len > 0:
    console_write(p, len)

proc kprint*(s: cstring) {.exportc, cdecl.} =
  if s != nil:
    let length = len(s)
    if length > 0:
      kwrite(cast[pointer](s), csize_t(length))

proc kprint_hex*(n: uint64) {.exportc, cdecl.} =
  const hex_chars = "0123456789ABCDEF"
  var buf: array[18, char]
  buf[0] = '0'
  buf[1] = 'x'
  for i in 0..15:
    let nibble = (n shr (60 - (i * 4))) and 0xF
    buf[i+2] = hex_chars[nibble]
  console_write(addr buf[0], 18)

proc kprintln*(s: cstring) {.exportc, cdecl.} =
  kprint(s); kprint("\n")

import fs/tar
import fs/sfs

# --- INITRD SYMBOLS ---
var binary_initrd_tar_start {.importc: "_binary_initrd_tar_start".}: char
var binary_initrd_tar_end {.importc: "_binary_initrd_tar_end".}: char

# =========================================================
# Shared Infrastructure
# =========================================================

const SYSTABLE_BASE = 0x83000000'u64

# Global Rings (The Pipes - L0 Physics)
var guest_rx_hal: HAL_Ring[IonPacket]
var guest_tx_hal: HAL_Ring[IonPacket]
var guest_event_hal: HAL_Ring[IonPacket]
var guest_cmd_hal: HAL_Ring[CmdPacket]

# Shared Channels (The Valves - L1 Logic)
# Shared Channels
var chan_rx*: SovereignChannel[IonPacket]
var chan_tx*: SovereignChannel[IonPacket]
var chan_event*: SovereignChannel[IonPacket]
var chan_cmd*: SovereignChannel[CmdPacket]
# chan_input is now imported from ion.nim!

proc ion_push_stdin*(p: pointer, len: csize_t) {.exportc, cdecl.} =
  ## Push raw console data into the Userland Input Ring

  # [FIX] Safety Guard
  if chan_input.ring == nil:
    return

  var pkt = ion_alloc()
  if pkt.data == nil: return

  let to_copy = min(int(len), 2048)
  copyMem(pkt.data, p, to_copy)
  pkt.len = uint16(to_copy)

  chan_input.send(pkt)

proc get_ion_load(): int =
  ## Calculate load of the Command Ring (The Heartbeat of the NPLs)
  let head = guest_cmd_hal.head
  let tail = guest_cmd_hal.tail
  let mask = guest_cmd_hal.mask
  return int((head - tail) and mask)

proc rumpk_yield_internal() {.cdecl, exportc.}

# HAL Driver API
proc hal_io_init() {.importc, cdecl.}
proc virtio_net_poll() {.importc, cdecl.}
proc virtio_net_send(data: pointer, len: uint32) {.importc, cdecl.}
proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.}
proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}
proc ion_free_raw(id: uint16) {.importc, cdecl.}
proc nexshell_main() {.importc, cdecl.}
proc ui_fiber_entry() {.importc, cdecl.}

proc get_now_ns(): uint64 =
  proc rumpk_timer_now_ns(): uint64 {.importc, cdecl.}
  return rumpk_timer_now_ns()

proc fiber_yield*() {.exportc, cdecl.} =
  rumpk_yield_internal()

proc fiber_sleep*(ms: int) {.exportc, cdecl.} =
  let now = get_now_ns()
  current_fiber.sleep_until = now + uint64(ms) * 1000000'u64
  fiber_yield()

proc rumpk_yield_internal() {.cdecl, exportc.} =
  let load = get_ion_load()
  let now = get_now_ns()

  # 🏛️ ADAPTIVE GOVERNOR (Phase 3: FLOOD CONTROL)
  if load > 200:
    if current_fiber != addr fiber_ion:
      switch(addr fiber_ion)
      return
  elif load > 0:
    if current_fiber == addr fiber_subject:
      switch(addr fiber_ion)
      return

  # Normal Round Robin logic with Sleep Check
  var next_fiber: Fiber = nil

  if current_fiber == addr fiber_ion:
    next_fiber = addr fiber_nexshell
  elif current_fiber == addr fiber_nexshell:
    next_fiber = addr fiber_ui
  elif current_fiber == addr fiber_ui:
    next_fiber = addr fiber_subject
  elif current_fiber == addr fiber_subject:
    next_fiber = addr fiber_watchdog
  else:
    next_fiber = addr fiber_ion

  # Skip sleeping fibers
  var found = false
  for _ in 0..5: # Max 5 check to avoid skip all
    if next_fiber != nil and now >= next_fiber.sleep_until:
      found = true
      break

    # Move to next in sequence
    if next_fiber == addr fiber_ion: next_fiber = addr fiber_nexshell
    elif next_fiber == addr fiber_nexshell: next_fiber = addr fiber_ui
    elif next_fiber == addr fiber_ui: next_fiber = addr fiber_subject
    elif next_fiber == addr fiber_subject: next_fiber = addr fiber_watchdog
    else: next_fiber = addr fiber_ion

  if found and next_fiber != current_fiber:
    switch(next_fiber)
  elif not found:
    asm "csrsi sstatus, 2"

# =========================================================
# ION Intelligence Fiber (Core System Supervisor)
# =========================================================

proc ion_fiber_entry() {.cdecl.} =
  hal_io_init()
  kprintln("[ION] Fiber 1 Reporting for Duty.")
  while true:
    # 1. Drain Command Channel -> Push to HW
    var cmd: CmdPacket
    while chan_cmd.recv(cmd):
      # Cortex Logic: Dispatch Commands
      case cmd.kind:
      of uint32(CmdType.CMD_GPU_MATRIX):
        let msg = if cmd.arg > 0: "ENGAGE" else: "DISENGAGE"
        kprintln("[Kernel] Matrix Protocol: ")
        kprintln(cstring(msg))
        matrix_enabled = (cmd.arg > 0)
      of uint32(CmdType.CMD_SYS_EXIT):
        kprint("[Kernel] Subject Exited. Status: ")
        kprint_hex(cmd.arg)
        kprintln("")
        kprintln("[Kernel] Respawning Shell...")
        subject_loading_path = "bin/nipbox"
        init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[
            0], stack_subject.len)
      of uint32(CmdType.CMD_ION_STOP):
        ion_paused = true
        pause_start = get_now_ns()
        kprintln("[Kernel] ION PAUSED by Watchdog.")
      of uint32(CmdType.CMD_ION_START):
        ion_paused = false
        kprintln("[Kernel] ION RESUMED.")
      of uint32(CmdType.CMD_GET_GPU_STATUS):
        let msg = if matrix_enabled: "STATUS: Matrix is ONLINE" else: "STATUS: Matrix is OFFLINE"
        kprintln("[Kernel] GPU Request")
        kprintln(cstring(msg))
      of uint32(CmdType.CMD_ION_FREE):
        # Userland is returning a packet
        ion_free_raw(uint16(cmd.arg))
      of uint32(CmdType.CMD_SYS_EXEC):
        kprintln("[Kernel] CMD_SYS_EXEC received!")
        let path_ptr = cast[cstring](cmd.arg)
        let path_str = $path_ptr
        kprint("[Kernel] Summoning: ")
        kprintln(cstring(path_str))
        subject_loading_path = path_str
        init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[
            0], stack_subject.len)
      of uint32(CmdType.CMD_NET_TX):
        let args = cast[ptr NetArgs](cmd.arg)
        virtio_net_send(cast[ptr UncheckedArray[byte]](args.buf), uint32(args.len))
      of uint32(CmdType.CMD_NET_RX):
        let args = cast[ptr NetArgs](cmd.arg)

        # 1. Poll Hardware (Injects into chan_rx if avail)
        virtio_net_poll()

        # 2. Check Software Channel
        var pkt: IonPacket
        if chan_rx.recv(pkt):
          # Copy packet to user buffer
          let copy_len = if uint64(pkt.len) > args.len: args.len else: uint64(pkt.len)
          copyMem(cast[pointer](args.buf), cast[pointer](pkt.data), copy_len)
          args.len = copy_len

          # Return Slab to Pool
          ion_free_raw(pkt.id)
        else:
          args.len = 0
      of uint32(CmdType.CMD_BLK_READ):
        let args = cast[ptr BlkArgs](cmd.arg)
        virtio_blk_read(args.sector, cast[pointer](args.buf))
      of uint32(CmdType.CMD_BLK_WRITE):
        let args = cast[ptr BlkArgs](cmd.arg)
        virtio_blk_write(args.sector, cast[pointer](args.buf))
      of uint32(CmdType.CMD_FS_WRITE):
        let args = cast[ptr FileArgs](cmd.arg)
        sfs_write_file(cast[cstring](args.name), cast[cstring](args.data), int(args.len))
      else:
        discard

    # 2. Yield to let Subject run
    fiber_yield()

# =========================================================
# Kernel Infrastructure Entry
# =========================================================

# =========================================================
# Kernel Infrastructure Entry
# = =========================================================

# HAL/NPL Entry points
proc rumpk_halt() {.importc, cdecl, noreturn.}

# Hardware Ingress (Zig -> Nim)
proc ion_get_virt(id: uint16): pointer {.importc, cdecl.}
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
  ## Intercept raw hardware packet and push to Sovereign RX Channel
  let data = ion_get_virt(id)
  var pkt = IonPacket(data: cast[ptr UncheckedArray[byte]](data), len: len, id: id)
  chan_rx.send(pkt)

# Panic Handler
proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
  kprintln("\n[PANIC] ")
  kprintln(msg)
  rumpk_halt()

# Include Watchdog Logic
include watchdog

# =========================================================
# kmain: The Orchestrator
# =========================================================

proc kmain() {.exportc, cdecl.} =
  kprintln("\n\n")
  kprintln("╔═══════════════════════════════════════╗")
  kprintln("║     NEXUS RUMK v1.1 - SOVEREIGN       ║")
  kprintln("╚═══════════════════════════════════════╝")

  # 1. Hardware & Memory
  kprintln("[Kernel] Initializing Memory Substrate...")
  ion_pool_init()

  # [FIX] Input Channel Init BEFORE Drivers
  ion_init_input()

  hal_io_init()

  # 1.1 VFS (InitRD)
  vfs_init(addr binary_initrd_tar_start, addr binary_initrd_tar_end)

  # 1.2 VFS (SFS)
  sfs_mount()

  # Wire VFS to SysTable (Hypercall Vector)
  let sys = cast[ptr SysTable](SYSTABLE_BASE)
  sys.fn_vfs_open = cast[pointer](ion_vfs_open)
  sys.fn_vfs_read = cast[pointer](ion_vfs_read)
  sys.fn_vfs_list = cast[pointer](ion_vfs_list)
  sys.fn_log = cast[pointer](kwrite)

  # 1.5 The Retina (VirtIO-GPU)
  proc virtio_gpu_init(base: uint64) {.importc, cdecl.}
  proc matrix_init() {.importc, cdecl.}

  # On QEMU virt machine, virtio-mmio devices are at 0x10001000-0x10008000
  # GPU could be at any slot.
  kprintln("[Kernel] Scanning for VirtIO-GPU...")
  for i in 1..8:
    let base_addr = 0x10000000'u64 + (uint64(i) * 0x1000'u64)
    virtio_gpu_init(base_addr)

  # Initial Matrix greeting
  matrix_init()

  # 2. Channel Infrastructure
  kprintln("[Kernel] Mapping Sovereign Channels...")

  # Initialize Invariant Shield (Masking)
  for r in [addr guest_rx_hal, addr guest_tx_hal, addr guest_event_hal]:
    r.head = 0
    r.tail = 0
    r.mask = 255

  guest_cmd_hal.head = 0
  guest_cmd_hal.tail = 0
  guest_cmd_hal.mask = 255
  # Input HAL init removed - handled by ion_init_input

  chan_rx.ring = addr guest_rx_hal
  chan_tx.ring = addr guest_tx_hal
  chan_event.ring = addr guest_event_hal
  chan_cmd.ring = addr guest_cmd_hal
  # chan_input ring set in ion_init_input

  let sys_table = cast[ptr SysTable](SYSTABLE_BASE)
  sys_table.magic = 0x4E585553
  sys_table.s_rx = addr guest_rx_hal
  sys_table.s_tx = addr guest_tx_hal
  sys_table.s_event = addr guest_event_hal
  sys_table.s_cmd = addr guest_cmd_hal
  sys_table.s_input = chan_input.ring # From global

  # 3. The Nerve (Yield Anchor)
  proc rumpk_yield_guard() {.importc, cdecl.}
  let yield_ptr_loc = cast[ptr pointer](0x83000FF0'u64)
  yield_ptr_loc[] = cast[pointer](rumpk_yield_guard)

  # 4. Deployment
  kprintln("[Kernel] Spawning System Fibers...")

  # 1. ION FIBER (The Valve)
  init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))

  # 2. NEXSHELL FIBER (The Brain)
  init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0],
      sizeof(stack_nexshell))

  # 3. UI FIBER (The Face)
  init_fiber(addr fiber_ui, ui_fiber_entry, addr stack_ui[0], sizeof(stack_ui))

  # 4. SUBJECT FIBER (The Payload)
  init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0],
      sizeof(stack_subject))

  # 5. WATCHDOG FIBER (The Immune System)
  init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))

  # [FIX] GLOBAL INTERRUPT ENABLE
  # Open the ear before we enter the loop.
  kprintln("[Kernel] Enabling Supervisor Interrupts (SIE)...")
  asm "csrsi sstatus, 2"

  kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")

  # Handover to Scheduler (The Heartbeat)
  switch(addr fiber_ion)

{.pop.}
