#[cfg(test)]
#[allow(deprecated)]
mod tests {
    use cgmath::vec3;
    use winit::{dpi::PhysicalPosition, event::{DeviceId, ElementState, Event, Force, KeyboardInput, ModifiersState, Touch, TouchPhase, WindowEvent}, window::WindowId};

    use crate::{config::LogConfig, input::InputState, util::intersect_triangle};
    use crate::input::vk_to_scan_code;

    fn epsilon_eq(f1: f32, f2: f32) {
        assert!(f32::abs(f1 - f2) < f32::EPSILON, "{} == {}", f1, f2);
    }

    fn epsilon_eq_option(o1: Option<f32>, o2: Option<f32>) {
        if let Some(f1) = o1 {
            if let Some(f2) = o2 {
                epsilon_eq(f1, f2);
            } else {
                panic!("Some({}) == None", f1);
            }
        } else if let Some(f2) = o2 {
            panic!("None == Some({})", f2);
        }
    }

    #[test]
    fn triangle_intersection() {
        let zero = vec3(0.0, 0.0, 0.0);
        let a = [2.0, 0.5, 0.5];
        let b = [2.0, -0.5, 0.5];
        let c = [2.0, 0.0, -0.5];

        let dist1 = intersect_triangle(zero, vec3(1.0, 0.0, 0.0), a, b, c);
        epsilon_eq_option(dist1, Some(2.0));

        let dist2 = intersect_triangle(zero, vec3(0.0, 0.0, 1.0), a, b, c);
        epsilon_eq_option(dist2, None);

        let dist3 = intersect_triangle(zero, vec3(0.9950371902, 0.09950371902, 0.0), a, b, c);
        epsilon_eq_option(dist3, Some(2.0099751242));
    }

    fn create_test_input_state() -> InputState {
        InputState::new("config/testinput.toml", LogConfig::from_file("config/log.toml"))
    }

    #[test]
    fn key_test() {
        let mut state = create_test_input_state();
        state.frame_start();
        state.frame_end();
        unsafe {
            state.on_window_event(&Event::WindowEvent{ window_id: WindowId::dummy(), event: WindowEvent::KeyboardInput {
                device_id: DeviceId::dummy(),
                input: KeyboardInput { scancode: 1, state: ElementState::Pressed, virtual_keycode: None, modifiers: ModifiersState::empty() },
                is_synthetic: true,
            }});
        }
        state.frame_start();
        assert_eq!(state.button_just_pressed("quit"), true);
        assert_eq!(state.button_down("quit"), true);
        state.frame_end();
        state.frame_start();
        assert_eq!(state.button_just_pressed("quit"), false);
        assert_eq!(state.button_down("quit"), true);
        state.frame_end();
        unsafe {
            state.on_window_event(&Event::WindowEvent{ window_id: WindowId::dummy(), event: WindowEvent::KeyboardInput {
                device_id: DeviceId::dummy(),
                input: KeyboardInput { scancode: 1, state: ElementState::Released, virtual_keycode: None, modifiers: ModifiersState::empty() },
                is_synthetic: true,
            }});
        }
        state.frame_start();
        assert_eq!(state.button_down("quit"), false);
        state.frame_end();
        unsafe {
            state.on_window_event(&Event::WindowEvent{ window_id: WindowId::dummy(), event: WindowEvent::KeyboardInput {
                device_id: DeviceId::dummy(),
                input: KeyboardInput { scancode: 32, state: ElementState::Pressed, virtual_keycode: None, modifiers: ModifiersState::empty() },
                is_synthetic: true,
            }});
        }
        state.frame_start();
        assert_eq!(state.button_down("button_right"), true);
    }

    fn touch_event(state: &mut InputState, phase: TouchPhase, id: u64) {
        unsafe {
            state.on_window_event(&Event::WindowEvent{ window_id: WindowId::dummy(), event: WindowEvent::Touch(Touch {
                device_id: DeviceId::dummy(), phase, location: PhysicalPosition::new(0., 0.), force: Some(Force::Normalized(0.5)), id
            })});
        }
    }

    #[test]
    fn touch_test() {
        let mut state = create_test_input_state();
        state.frame_start();
        state.frame_end();
        touch_event(&mut state, TouchPhase::Started, 1);
        state.frame_start();
        assert_eq!(state.button_just_pressed("touchclick"), true);
        assert_eq!(state.button_down("touchclick"), true);
        state.frame_end();
        touch_event(&mut state, TouchPhase::Moved, 1);
        state.frame_start();
        assert_eq!(state.button_just_pressed("touchclick"), false);
        assert_eq!(state.button_down("touchclick"), true);
        state.frame_end();
        touch_event(&mut state, TouchPhase::Ended, 1);
        state.frame_start();
        assert_eq!(state.button_just_released("touchclick"), true);
        assert_eq!(state.button_down("touchclick"), false);
        state.frame_end();
    }

    #[test]
    fn multi_touch_test() {
        let mut state = create_test_input_state();
        state.frame_start();
        state.frame_end();
        touch_event(&mut state, TouchPhase::Started, 2);
        // TODO: add tolerance for delay
        touch_event(&mut state, TouchPhase::Started, 3);
        state.frame_start();
        assert_eq!(state.button_just_pressed("touchclick"), false);
        assert_eq!(state.button_down("touchclick"), false);
        assert_eq!(state.button_just_pressed("doubletouchclick"), true);
        assert_eq!(state.button_down("doubletouchclick"), true);
        state.frame_end();
        touch_event(&mut state, TouchPhase::Moved, 2);
        state.frame_start();
        assert_eq!(state.button_just_pressed("doubletouchclick"), false);
        assert_eq!(state.button_down("doubletouchclick"), true);
        state.frame_end();
        touch_event(&mut state, TouchPhase::Ended, 2);
        state.frame_start();
        assert_eq!(state.button_just_released("doubletouchclick"), true);
        assert_eq!(state.button_down("doubletouchclick"), false);
        assert_eq!(state.button_just_pressed("touchclick"), false);
        // TODO: don't enable button_down on release of double touch
        // assert_eq!(state.button_down("touchclick"), false);
        state.frame_end();
        touch_event(&mut state, TouchPhase::Ended, 3);
        state.frame_start();
        // TODO: only set button_just_released for one frame
        // assert_eq!(state.button_just_released("doubletouchclick"), false);
        assert_eq!(state.button_down("doubletouchclick"), false);
    }

    #[test]
    fn vk_input_name_test() {
        let vk = "VK_ESCAPE";
        assert_eq!(vk_to_scan_code(vk), Some(1));
    }
}