use bevy::{prelude::*, utils::HashSet};

use crate::camera::DebugCamOffset;

#[derive(Default, Debug, Resource)]
pub(crate) struct InputState {
    pub yaw: f32,
    pub throttle: f32,
    pub brake: bool,
    pub pitch: f32,
}

fn update_debug_cam(mut offset: ResMut<DebugCamOffset>, mut keys: ResMut<Input<KeyCode>>) {
    let keyset: HashSet<_> = keys.get_pressed().collect();
    let shifted = keyset.contains(&KeyCode::LShift) || keyset.contains(&KeyCode::RShift);

    for key in keyset {
        match key {
            KeyCode::Left => offset.rot -= 5.0,
            KeyCode::Right => offset.rot += 5.0,
            KeyCode::Up => {
                if shifted {
                    offset.alt += 0.5;
                } else {
                    offset.dist -= 0.5;
                }
            }
            KeyCode::Down => {
                if shifted {
                    offset.alt -= 0.5;
                } else {
                    offset.dist += 0.5;
                }
            }
            _ => continue,
        }
    }

    if keys.get_just_released().len() > 0 {
        let unpressed = keys.just_released(KeyCode::LShift) || keys.just_released(KeyCode::RShift);
        keys.reset_all();
        if shifted && !unpressed {
            keys.press(KeyCode::LShift);
        }
    }
}

fn update_input(mut events: EventReader<GamepadEvent>, mut istate: ResMut<InputState>) {
    for GamepadEvent {
        gamepad: _,
        event_type: ev,
    } in events.iter()
    {
        match *ev {
            GamepadEventType::ButtonChanged(GamepadButtonType::RightTrigger2, val) => {
                istate.throttle = val;
            }
            GamepadEventType::ButtonChanged(GamepadButtonType::LeftTrigger2, val) => {
                istate.throttle = -val;
            }
            GamepadEventType::ButtonChanged(GamepadButtonType::East, val) => {
                if val > 0.5 {
                    istate.brake = true;
                } else {
                    istate.brake = false;
                }
            }
            GamepadEventType::AxisChanged(GamepadAxisType::LeftStickX, val) => {
                istate.yaw = val;
            }
            // ignore spurious vertical movement for now
            GamepadEventType::AxisChanged(GamepadAxisType::LeftStickY, val) => {
                istate.pitch = val;
            }
            _ => {
                info!("unhandled gamepad event: {:?}", ev);
            }
        }
    }

    //dbg!(&istate);
}

pub struct CyberInputPlugin;
impl Plugin for CyberInputPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<InputState>()
            .add_system(update_input)
            .add_system(update_debug_cam);
    }
}
