use std::{
    f32::consts::PI,
    time::{Duration, Instant},
};

use rand::random;
use sdl2::{event::Event, keyboard::Keycode};

use crate::util::rescale;

use super::OutputLayer;

pub struct HeadMover {
    movement_duration: Duration,
    last_timestamp: Instant,
    targets: [(f32, f32); 4],
}

impl HeadMover {
    pub fn new(movement_duration: Duration) -> Self {
        Self {
            movement_duration,
            last_timestamp: Instant::now() - movement_duration,
            targets: Default::default(),
        }
    }
}

fn sample_random_point() -> (f32, f32) {
    let pan = rescale(random::<f32>(), (0.0, 1.0), (-0.5 * PI, 0.5 * PI));
    let tilt = random::<f32>().acos();

    (pan, tilt)
}

impl OutputLayer for HeadMover {
    fn tick(&mut self, _dt: Duration) {
        let now = Instant::now();
        if now - self.last_timestamp >= self.movement_duration {
            for target in self.targets.iter_mut() {
                *target = sample_random_point();
            }
            self.last_timestamp = now;
        }
    }

    fn draw_sdl(
        &self,
        _canvas: &mut sdl2::render::Canvas<sdl2::video::Window>,
        _texture_size: u32,
    ) {
    }

    fn on_sdl_event(&mut self, event: &sdl2::event::Event) {
        match event {
            Event::KeyDown {
                keycode: Some(Keycode::Return),
                ..
            } => {
                let now = Instant::now();
                for target in self.targets.iter_mut() {
                    *target = sample_random_point();
                }
                self.last_timestamp = now;
            }

            _ => {}
        }
    }

    fn update_dmx(&self, output: &mut [crate::fixtures::MovingHead; 4]) {
        for (head, target) in output.iter_mut().zip(self.targets.iter()) {
            let (pan, tilt) = target;
            head.pan = *pan;
            head.tilt = *tilt;
        }
    }
}
