// 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 HAL: Matrix Protocol (Rainmaker Logic)
//!
//! Implements a "Matrix" falling rain effect for the boot splash.
//! Recedes into the background after a fixed lifetime.
//!
//! SAFETY: Uses a simple Xorshift PRNG. Animation state is global.

const std = @import("std");
const fb = @import("framebuffer.zig");

// Config
const FONT_W = 8;
const FONT_H = 8;
const COLS = fb.WIDTH / FONT_W;
const LIFETIME_FRAMES = 150; // ~5 seconds at 30FPS (reduced for impact)

// State
// SAFETY(Matrix): Drops array is initialized by `init()` before use.
// Initialized to `undefined` to save a 512B zero-sweep in BSS.
var drops: [COLS]i32 = undefined;
var frame_count: usize = 0;
var is_active: bool = false;

// Basic PRNG (Xorshift)
var rng_state: u32 = 0xDEADBEEF;
fn random() u32 {
    var x = rng_state;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    rng_state = x;
    return x;
}

pub fn init() void {
    is_active = true;
    frame_count = 0;
    // Initialize drops at random heights off-screen
    var i: usize = 0;
    while (i < COLS) : (i += 1) {
        drops[i] = -@as(i32, @intCast(random() % 100));
    }
}

// Returns: TRUE if still animating, FALSE if finished (The Void)
pub fn update() bool {
    if (!is_active) return false;

    // 1. Fade existing trails
    fb.fade_screen(15); // Fade speed

    // 2. Are we dying?
    frame_count += 1;
    const dying = (frame_count > LIFETIME_FRAMES);

    // 3. Update Drops
    var active_drops: usize = 0;
    var i: usize = 0;
    while (i < COLS) : (i += 1) {
        // Draw Head (Bright White/Green)
        const x = i * FONT_W;
        const y = drops[i];

        if (y >= 0 and y < @as(i32, @intCast(fb.HEIGHT))) {
            // Draw a simple "pixel block" glyph
            // White tip
            fb.put_pixel(@intCast(x + 3), @intCast(y + 3), 0xFFFFFFFF);
            fb.put_pixel(@intCast(x + 4), @intCast(y + 3), 0xFFFFFFFF);
            fb.put_pixel(@intCast(x + 3), @intCast(y + 4), 0xFFFFFFFF);
            fb.put_pixel(@intCast(x + 4), @intCast(y + 4), 0xFFFFFFFF);

            // Green body follow
            if (y > 8) {
                fb.fill_rect(@intCast(x + 3), @intCast(y - 4), 2, 4, 0xFF00FF00);
            }
        }

        // Move down
        drops[i] += FONT_H;

        // Reset if off screen
        if (drops[i] > @as(i32, @intCast(fb.HEIGHT))) {
            if (!dying) {
                // Respawn at top
                drops[i] = -@as(i32, @intCast(random() % 50));
                active_drops += 1;
            } else {
                // Do NOT respawn. Let it fall into the void.
            }
        } else {
            active_drops += 1; // It's still on screen
        }
    }

    // 4. Check for Total Extinction
    if (dying and active_drops == 0) {
        // Ensure pure black at the end
        fb.clear(0xFF000000);
        is_active = false;
        return false; // STOP THE GPU FLUSHING IF IDLE
    }

    return true; // Keep animating
}

// --- EXPORTS FOR NIM ---
export fn matrix_init() void {
    init();
}

export fn matrix_update() bool {
    return update();
}
