// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation

//! Rumpk Layer 0: UART Input Logic (Kernel Only)
//!
//! Separated from uart.zig to avoid polluting userland stubs with kernel dependencies.

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

// Input Ring Buffer (256 bytes, power of 2 for fast masking)
const INPUT_BUFFER_SIZE = 256;
var input_buffer: [INPUT_BUFFER_SIZE]u8 = undefined;
var input_head = std.atomic.Value(u32).init(0); // Write position
var input_tail = std.atomic.Value(u32).init(0); // Read position

pub fn poll_input() void {
    // Only Kernel uses this
    const Kernel = struct {
        extern fn ion_push_stdin(ptr: [*]const u8, len: usize) void;
        extern fn kprint(s: [*]const u8) void;
    };

    switch (builtin.cpu.arch) {
        .riscv64 => {
            const thr: *volatile u8 = @ptrFromInt(uart.NS16550A_BASE + uart.NS16550A_THR);
            const lsr: *volatile u8 = @ptrFromInt(uart.NS16550A_BASE + uart.NS16550A_LSR);

            // Read all available bytes from UART FIFO (Limit 128 to prevent stall)
            var loop_limit: usize = 0;
            while ((lsr.* & 0x01) != 0 and loop_limit < 128) { // Data Ready
                loop_limit += 1;
                const byte = thr.*;
                const byte_arr = [1]u8{byte};

                // DEBUG: Trace hardware read
                Kernel.kprint("[HW Read]\n");

                // Forward to Kernel Input Channel
                Kernel.ion_push_stdin(&byte_arr, 1);

                // Add to ring buffer if not full
                const head_val = input_head.load(.monotonic);
                const tail_val = input_tail.load(.monotonic);
                const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;

                if (next_head != tail_val) {
                    input_buffer[head_val] = byte;
                    input_head.store(next_head, .monotonic);
                }
            }
        },
        .aarch64 => {
            const dr: *volatile u32 = @ptrFromInt(uart.PL011_BASE + uart.PL011_DR);
            const fr: *volatile u32 = @ptrFromInt(uart.PL011_BASE + uart.PL011_FR);

            while ((fr.* & (1 << 4)) == 0) { // RXFE (Receive FIFO Empty) is bit 4
                const byte: u8 = @truncate(dr.*);
                const byte_arr = [1]u8{byte};
                Kernel.ion_push_stdin(&byte_arr, 1);

                const head_val = input_head.load(.monotonic);
                const tail_val = input_tail.load(.monotonic);
                const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;

                if (next_head != tail_val) {
                    input_buffer[head_val] = byte;
                    input_head.store(next_head, .monotonic);
                }
            }
        },
        else => {},
    }
}

export fn uart_poll_input() void {
    poll_input();
}

pub fn read_byte() ?u8 {
    // First, poll UART to refill buffer
    poll_input();

    // Then read from buffer
    const head_val = input_head.load(.monotonic);
    const tail_val = input_tail.load(.monotonic);

    if (tail_val != head_val) {
        const byte = input_buffer[tail_val];
        input_tail.store((tail_val + 1) % INPUT_BUFFER_SIZE, .monotonic);
        return byte;
    }

    return null;
}
