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

//! Rumpk Layer 0: libc Stubs (Bump Allocator)
//!
//! We are the standard library now. Provides malloc/free/realloc/calloc
//! for libraries that expect libc (e.g., LwIP).
//!
//! DECISION(Alloc): Bump allocator chosen for simplicity and determinism.
//! Memory is never reclaimed; system reboots to reset.

const uart = @import("uart.zig");

// Sovereign timer — canonical time source for the entire kernel
extern fn rumpk_timer_now_ns() u64;

// =========================================================
// Heap Stubs (Bump Allocator with Block Headers)
// =========================================================

// Simple Bump Allocator for L0
// SAFETY(Heap): Memory is written by malloc before any read occurs.
// Initialized to `undefined` to avoid zeroing 32MB at boot.
var heap: [16 * 1024 * 1024]u8 align(4096) = undefined;
var heap_idx: usize = 0;
var heap_init_done: bool = false;

export fn debug_print(s: [*]const u8, len: usize) void {
    uart.print(s[0..len]);
}

// Support for C-shim printf (clib.c)
// REMOVED: Already exported by entry_riscv.zig (hal.o)
// export fn hal_console_write(ptr: [*]const u8, len: usize) void {
//     uart.print(ptr[0..len]);
// }

// Header structure (64 bytes aligned to match LwIP MEM_ALIGNMENT)
const BlockHeader = struct {
    size: usize,
    _pad: [64 - @sizeOf(usize)]u8,
};

export fn malloc(size: usize) ?*anyopaque {
    if (size == 0) return null;

    if (!heap_init_done) {
        if (heap_idx != 0) {
            uart.print("[Alloc] WARNING: BSS NOT ZEROED! heap_idx: ");
            uart.print_hex(heap_idx);
            uart.print("\n");
            heap_idx = 0;
        }
        heap_init_done = true;
    }

    const total_needed = size + @sizeOf(BlockHeader);
    const align_mask: usize = 63; // 64-byte alignment
    const aligned_idx = (heap_idx + align_mask) & ~align_mask;

    if (aligned_idx + total_needed > heap.len) {
        uart.print("[Alloc] OOM! Size: ");
        uart.print_hex(size);
        uart.print(" Used: ");
        uart.print_hex(heap_idx);
        uart.print("\n");
        return null;
    }

    // Trace allocations (disabled to reduce noise)
    uart.print("[Alloc] ");
    uart.print_hex(size);
    uart.print(" -> Used: ");
    uart.print_hex(aligned_idx + total_needed);
    uart.print("\n");

    const base_ptr = &heap[aligned_idx];
    const header = @as(*BlockHeader, @ptrCast(@alignCast(base_ptr)));
    header.size = size;

    heap_idx = aligned_idx + total_needed;
    return @as(*anyopaque, @ptrFromInt(@intFromPtr(base_ptr) + @sizeOf(BlockHeader)));
}

export fn free(ptr: ?*anyopaque) void {
    // Bump allocator: no-op free.
    _ = ptr;
}

export fn realloc(ptr: ?*anyopaque, size: usize) ?*anyopaque {
    if (ptr == null) return malloc(size);
    if (size == 0) {
        free(ptr);
        return null;
    }

    // Retrieve old size from header
    const base_addr = @intFromPtr(ptr.?) - @sizeOf(BlockHeader);
    const header = @as(*BlockHeader, @ptrFromInt(base_addr));
    const old_size = header.size;

    // Optimization: If new size is smaller and it's the last block, we could shrink?
    // But for a bump allocator, just allocate new.
    const new_ptr = malloc(size);
    if (new_ptr) |np| {
        const copy_size = if (size < old_size) size else old_size;
        const src = @as([*]const u8, @ptrCast(ptr.?));
        const dst = @as([*]u8, @ptrCast(np));

        var i: usize = 0;
        while (i < copy_size) : (i += 1) {
            dst[i] = src[i];
        }

        free(ptr);
        return np;
    }
    return null;
}

export fn calloc(nmemb: usize, size: usize) ?*anyopaque {
    const total = nmemb * size;
    const ptr = malloc(total);
    if (ptr) |p| {
        const dst = @as([*]u8, @ptrCast(p));
        var i: usize = 0;
        while (i < total) : (i += 1) {
            dst[i] = 0;
        }
    }
    return ptr;
}

// =========================================================
// Rumpk Runtime Support
// =========================================================

export fn get_ticks() u32 {
    // Delegate to sovereign timer — single source of truth for all time
    const ns = rumpk_timer_now_ns();
    return @truncate(ns / 1_000_000); // ns → ms
}

// export fn rumpk_timer_set_ns(ns: u64) void {
//     // Stub: Timer not implemented in L0 yet
//     _ = ns;
// }

export fn fb_kern_get_addr() usize {
    return 0; // Stub: No framebuffer
}

export fn nexshell_main() void {
    uart.print("[Kernel] NexShell Stub Executed\n");
}
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;

// export fn exit(code: c_int) noreturn {
//     _ = code;
//     while (true) asm volatile ("wfi");
// }

// =========================================================
// Atomic Stubs (To resolve linker errors with libcompiler_rt)
// =========================================================

export fn __atomic_compare_exchange(len: usize, ptr: ?*anyopaque, expected: ?*anyopaque, desired: ?*anyopaque, success: c_int, failure: c_int) bool {
    _ = len;
    _ = ptr;
    _ = expected;
    _ = desired;
    _ = success;
    _ = failure;
    return true;
}

export fn __atomic_fetch_add_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_sub_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_and_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_or_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_xor_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_nand_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_umax_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_fetch_umin_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_load_16(ptr: ?*const anyopaque, model: c_int) u128 {
    _ = ptr;
    _ = model;
    return 0;
}

export fn __atomic_store_16(ptr: ?*anyopaque, val: u128, model: c_int) void {
    _ = ptr;
    _ = val;
    _ = model;
}

export fn __atomic_exchange_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
    _ = ptr;
    _ = val;
    _ = model;
    return 0;
}

export fn __atomic_compare_exchange_16(ptr: ?*anyopaque, exp: ?*anyopaque, des: u128, weak: bool, success: c_int, failure: c_int) bool {
    _ = ptr;
    _ = exp;
    _ = des;
    _ = weak;
    _ = success;
    _ = failure;
    return true;
}

// =========================================================
// Nim Runtime Stubs
// =========================================================

export fn setLengthStr() void {}
export fn addChar() void {}
export fn callDepthLimitReached__OOZOOZOOZOOZOOZOOZOOZOOZOOZusrZlibZnimZsystem_u3026() void {
    while (true) {}
}

export var NTIdefect__SEK9acOiG0hv2dnGQbk52qg_: ?*anyopaque = null;
