use std::time::Instant;

use glc::{
    array_buffer::{ArrayBuffer, Target, Usage},
    error::Error,
};

pub struct Uniform {
    buffer: ArrayBuffer,
    start_time: Instant,
}

#[repr(C, packed)]
struct Data {
    time: f32,
}

impl Uniform {
    pub fn new() -> Result<Self, Error> {
        let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?;
        buffer.buffer_data(Usage::StaticDraw, &[Data { time: 0.0 }])?;

        Ok(Self {
            buffer,
            start_time: Instant::now(),
        })
    }

    pub fn update(&mut self) -> Result<(), Error> {
        let time = Instant::now().duration_since(self.start_time).as_secs_f32();

        let mut data = self.buffer.map_mut::<Data>(true)?;

        data[0].time = time;

        Ok(())
    }

    pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> {
        Error::checked(|| self.buffer.bind_buffer_base(index))
    }
}
