use std::sync::Mutex;

use crate::time;

static RNG: Mutex<XorShift64> = Mutex::new(XorShift64::default());

pub fn shuffle_rng() {
    let mut rng = RNG.lock().expect("RNG mutex is poisoned.");
    rng.inject_time();
}

pub fn random_numeric_string(length: usize) -> String {
    let mut out = String::new();

    while out.len() < length {
        let num = random_number();
        out.push_str(&num.to_string());
    }

    out[..length].to_string()
}

pub fn random_number() -> u64 {
    let mut rng = RNG.lock().expect("RNG mutex is poisoned.");
    rng.inject_time();
    rng.next()
}

struct XorShift64 {
    state: u64,
}

impl XorShift64 {
    const fn new(seed: u64) -> Self {
        Self { state: seed }
    }

    const fn default() -> Self {
        Self::new(49)
    }

    fn inject_time(&mut self) {
        self.state ^= time::time_millis() as u64 % 1000;
    }

    fn next(&mut self) -> u64 {
        self.state ^= self.state << 13;
        self.state ^= self.state >> 7;
        self.state ^= self.state << 17;
        self.state
    }
}

impl Default for XorShift64 {
    fn default() -> Self {
        Self::default()
    }
}
