use std::collections::HashMap;

pub const PERF_COUNTER_SIZE: usize = 100;
pub static mut PERF_COUNTERS: Option<HashMap<String, PerformanceCounter>> = None;

pub struct PerformanceCounter {
    pub values: [u128; PERF_COUNTER_SIZE],
    pub index: usize,
}

pub fn stddev(arr: &[u128; PERF_COUNTER_SIZE], mean: i128) -> f64 {
    f64::sqrt(arr.iter().fold(0, |acc, b| acc + (*b as i128 - mean) * (*b as i128 - mean)) as f64 / PERF_COUNTER_SIZE as f64)
}

impl PerformanceCounter {
    pub fn mean(&self) -> u128 {
        self.values.iter().sum::<u128>() / PERF_COUNTER_SIZE as u128
    }

    pub fn init_perf() {
        unsafe {
            if PERF_COUNTERS.is_none() { PERF_COUNTERS = Some(HashMap::new()); }
        }
    }

    pub fn write_perf(name: &str, value: u128) {
        unsafe {
            if let Some(pcs) = &mut PERF_COUNTERS {
                if let Some(pc) = pcs.get_mut(name) {
                    pc.values[pc.index] = value;
                } else {
                    let mut pc = PerformanceCounter { values: [0; PERF_COUNTER_SIZE], index: 0 };
                    pc.values[0] = value;
                    pcs.insert(name.to_string(), pc);
                }
            }
        }
    }

    pub fn _get_perf(name: &str) -> u128 {
        unsafe {
            if let Some(pcs) = &mut PERF_COUNTERS {
                if let Some(pc) = pcs.get_mut(name) {
                    pc.mean()
                } else {
                    0
                }
            } else {
                0
            }
        }
    }

    pub fn perf_next_frame(name: &str) {
        unsafe {
            if let Some(pcs) = &mut PERF_COUNTERS {
                if let Some(pc) = pcs.get_mut(name) {
                    pc.index = (pc.index + 1) % PERF_COUNTER_SIZE;
                    pc.values[pc.index] = 0;
                }
            }
        }
    }
}