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

/**
 * @file sys_arch.c
 * @brief lwIP System Architecture Layer (NO_SYS Mode)
 * 
 * The Membrane Graft: This provides the minimal OS abstraction layer
 * required by lwIP in NO_SYS=1 mode (single-threaded, event-driven).
 * 
 * Architecture Philosophy:
 * - NO threading primitives (NO_SYS=1)
 * - Time via kernel syscall (not rdtime)
 * - No critical sections needed (single fiber context)
 */

#include <stdarg.h>
#include <stddef.h>
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/sys.h"
#include "lwip/stats.h"

extern int vprintf(const char *format, va_list args);

// =========================================================
// External Kernel Interface
// =========================================================

// Syscall to get monotonic time in nanoseconds from kernel
extern uint64_t syscall_get_time_ns(void);

// Console output for diagnostics
extern void console_write(const void* p, unsigned long len);

// =========================================================
// Time Source (The Heartbeat)
// =========================================================

/**
 * sys_now - Required by lwIP for timeout tracking
 * @return Current time in milliseconds
 * 
 * CRITICAL: This must be monotonic and never wrap backwards.
 * We use the kernel's high-resolution timer via syscall.
 */
u32_t sys_now(void) {
    // Get nanoseconds from kernel, convert to milliseconds
    uint64_t ns = syscall_get_time_ns();
    return (u32_t)(ns / 1000000ULL);
}

// =========================================================
// Initialization
// =========================================================

/**
 * sys_init - Called once during lwIP startup
 * 
 * In NO_SYS mode, this is a no-op. No threads to initialize.
 */
void sys_init(void) {
    // Membrane is already initialized by ion_user_init()
    // Nothing to do here for lwIP
}

// =========================================================
// Critical Sections (NO-OP in Single-Threaded Mode)
// =========================================================

#if SYS_LIGHTWEIGHT_PROT

/**
 * sys_arch_protect - Enter critical section
 * @return Protection state (unused in NO_SYS mode)
 * 
 * NO_SYS mode runs in a single fiber context.
 * No preemption possible within the Membrane event loop.
 */
sys_prot_t sys_arch_protect(void) {
    return 0;
}

/**
 * sys_arch_unprotect - Exit critical section
 * @param pval Protection state to restore
 */
void sys_arch_unprotect(sys_prot_t pval) {
    (void)pval; // Unused
}

#endif /* SYS_LIGHTWEIGHT_PROT */

// =========================================================
// Diagnostics (Optional)
// =========================================================

// =========================================================
// Diagnostics
// =========================================================

/**
 * lwip_platform_diag - Output diagnostic message
 * Used by LWIP_PLATFORM_DIAG() macro
 */
void lwip_platform_diag(const char *fmt, ...) {
    console_write("<<<LwIP>>> ", 11);
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

// =========================================================
// Assertions (Contract Enforcement)
// =========================================================

/**
 * lwip_platform_assert - Handle failed assertions
 * @param msg Assertion message
 * 
 * Note: Mapped via LWIP_PLATFORM_ASSERT macro in cc.h
 */
void lwip_platform_assert_impl(const char *msg) {
    const char panic_msg[] = "[lwIP ASSERT FAILED]\n";
    console_write(panic_msg, sizeof(panic_msg) - 1);
    console_write(msg, __builtin_strlen(msg));
    
    // Trigger kernel panic via syscall
    extern void syscall_panic(void) __attribute__((noreturn));
    syscall_panic();
}
