// 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.

//! Nexus Membrane: ION Interface (The Sovereign Protocol)
//!
//! Defines the shared memory interface, packet structures, and command types
//! used for communication between the kernel and userland.
//!
//! SAFETY: Implements lock-free ring buffers for the SysTable channels.
//! All memory accesses to the SysTable are through volatile pointers.

const std = @import("std");

// --- Protocol Definitions (Match core/ion.nim) ---

pub const CMD_SYS_NOOP: u32 = 0;
pub const CMD_SYS_EXIT: u32 = 1;
pub const CMD_ION_STOP: u32 = 2;
pub const CMD_ION_START: u32 = 3;
pub const CMD_GPU_MATRIX: u32 = 0x100;
pub const CMD_GPU_CLEAR: u32 = 0x101;
pub const CMD_GET_GPU_STATUS: u32 = 0x102;
pub const CMD_FS_OPEN: u32 = 0x200;
pub const CMD_FS_READ: u32 = 0x201;
pub const CMD_FS_READDIR: u32 = 0x202;
pub const CMD_ION_FREE: u32 = 0x300;
pub const CMD_SYS_EXEC: u32 = 0x400;
pub const CMD_NET_TX: u32 = 0x500;
pub const CMD_NET_RX: u32 = 0x501;
pub const CMD_BLK_READ: u32 = 0x600;
pub const CMD_BLK_WRITE: u32 = 0x601;

pub const CmdPacket = extern struct {
    kind: u32,
    _pad: u32, // Explicit Padding for 8-byte alignment
    arg: u64,
    id: u128, // SipHash Provenance (16 bytes)
};

// Compile-time validation: 32 bytes
comptime {
    if (@sizeOf(CmdPacket) != 32) {
        @compileError("CmdPacket size mismatch! Expected 32, got " ++ @as([]const u8, &[_]u8{@sizeOf(CmdPacket)}));
    }
}

pub const FsReadArgs = extern struct {
    fd: u64,
    buffer: u64,
    len: u64,
};

pub const NetArgs = extern struct {
    buf: u64,
    len: u64,
};

pub const BlkArgs = extern struct {
    sector: u64,
    buf: u64,
    len: u64,
};

pub const IonPacket = extern struct {
    data: u64, // ptr
    phys: u64,
    len: u16,
    id: u16,
};

// Generic Lock-Free Ring Buffer (Single Producer / Single Consumer safe)
pub fn RingBuffer(comptime T: type) type {
    return extern struct {
        head: u32,
        tail: u32,
        mask: u32,
        data: [256]T,

        pub fn push(self: *volatile @This(), item: T) bool {
            const head = self.head;
            const tail = self.tail;
            const mask = self.mask;

            // Check full
            if (((head + 1) & mask) == (tail & mask)) {
                return false;
            }

            // Write data
            self.data[head & mask] = item;

            // Commit
            asm volatile ("fence" ::: .{ .memory = true });
            self.head = (head + 1) & mask;
            return true;
        }
    };
}

pub const SysTable = extern struct {
    magic: u32,
    reserved: u32,
    s_rx: *RingBuffer(IonPacket),
    s_tx: *RingBuffer(IonPacket),
    s_event: *RingBuffer(IonPacket),
    s_cmd: *RingBuffer(CmdPacket),
    s_input: *RingBuffer(IonPacket),
    // Hypercalls
    fn_vfs_open: u64,
    fn_vfs_read: u64,
    fn_vfs_list: u64,
    fn_vfs_write: u64,
    fn_vfs_close: u64,
    fn_log: u64,
    fn_pledge: u64,
    // Framebuffer
    fb_addr: u64,
    fb_width: u32,
    fb_height: u32,
    fb_stride: u32,
    fb_bpp: u32,
    fn_yield: u64,
    // Crypto
    fn_siphash: u64,
    fn_ed25519_verify: u64,
    // Network
    s_net_rx: *RingBuffer(IonPacket),
    s_net_tx: *RingBuffer(IonPacket),

    // Phase 36.3: Shared ION (16 bytes)
    fn_ion_alloc: u64,
    fn_ion_free: u64,
};

comptime {
    if (@sizeOf(IonPacket) != 24) @compileError("IonPacket size mismatch!");
    if (@sizeOf(SysTable) != 184) {
        @compileError("SysTable size mismatch! Expected 184");
    }
}

const SYSTABLE_ADDR: usize = 0x83000000;

// --- API ---

extern fn console_write(ptr: [*]const u8, len: usize) void;

pub fn sys_cmd_push(pkt: CmdPacket) bool {
    const sys = @as(*const volatile SysTable, @ptrFromInt(SYSTABLE_ADDR));

    // Debug: Check magic
    if (sys.magic != 0x4E585553) {
        const msg = "[DEBUG] SysTable magic check FAILED!\n";
        console_write(msg.ptr, msg.len);
        return false;
    }

    // const msg2 = "[DEBUG] Pushing to command ring...\n";
    // console_write(msg2.ptr, msg2.len);

    // Push to Command Ring
    const result = sys.s_cmd.push(pkt);

    // if (result) {
    //     const msg3 = "[DEBUG] Command ring push SUCCESS\n";
    //     console_write(msg3.ptr, msg3.len);
    // } else {
    //     const msg4 = "[DEBUG] Command ring push FAILED (ring full?)\n";
    //     console_write(msg4.ptr, msg4.len);
    // }

    return result;
}

pub fn sys_input_pop(out_pkt: *IonPacket) bool {
    const sys = @as(*const volatile SysTable, @ptrFromInt(SYSTABLE_ADDR));
    if (sys.magic != 0x4E585553) return false;

    const ring = sys.s_input;
    const head = @atomicLoad(u32, &ring.head, .acquire);
    const tail = @atomicLoad(u32, &ring.tail, .monotonic);

    if (head == tail) return false;

    out_pkt.* = ring.data[tail & ring.mask];
    @atomicStore(u32, &ring.tail, tail + 1, .release);
    return true;
}
