use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GestureEvent
{
    pub gesture_id:    u64,
    pub phase:         GesturePhase,
    #[serde(rename = "type")]
    pub gesture_type:  GestureType,
    pub pointer_count: u8,
    pub origin:        Vec2,
    pub position:      Vec2,
    pub delta:         Vec2,
    pub velocity:      Vec2,
    pub direction:     Direction,
    pub edge:          Edge,
    pub progress:      f32,
    pub elapsed_ms:    u32,
    pub state_flags:   u8,
}

impl GestureEvent
{
    pub fn holding( &self ) -> bool { self.state_flags & StateFlags::HOLDING != 0 }
    pub fn fling( &self ) -> bool { self.state_flags & StateFlags::FLING != 0 }
    pub fn axis_locked_x( &self ) -> bool { self.state_flags & StateFlags::AXIS_LOCKED_X != 0 }
    pub fn axis_locked_y( &self ) -> bool { self.state_flags & StateFlags::AXIS_LOCKED_Y != 0 }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GesturePhase
{
    Start,
    Update,
    End,
    Cancel,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GestureType
{
    Tap,
    DoubleTap,
    LongPress,
    Pan,
    Swipe,
    Pinch,
    EdgePull,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Direction
{
    None,
    Up,
    Down,
    Left,
    Right,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Edge
{
    None,
    Top,
    Bottom,
    Left,
    Right,
}

pub struct StateFlags;
impl StateFlags
{
    pub const HOLDING:      u8 = 0b0001;
    pub const FLING:        u8 = 0b0010;
    pub const AXIS_LOCKED_X: u8 = 0b0100;
    pub const AXIS_LOCKED_Y: u8 = 0b1000;
}

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
pub struct Vec2
{
    pub x: f32,
    pub y: f32,
}

impl Vec2
{
    pub fn new( x: f32, y: f32 ) -> Self { Self { x, y } }
    pub fn length( &self ) -> f32 { ( self.x * self.x + self.y * self.y ).sqrt() }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GestureConfig
{
    pub edge_threshold_px:      f32,
    pub hold_threshold_ms:      u32,
    pub min_swipe_distance_px:  f32,
    pub min_swipe_velocity:     f32,
    pub axis_lock_threshold:    f32,
}

impl Default for GestureConfig
{
    fn default() -> Self
    {
        Self
        {
            edge_threshold_px:     30.0,
            hold_threshold_ms:     500,
            min_swipe_distance_px: 50.0,
            min_swipe_velocity:    2.0,
            axis_lock_threshold:   1.5,
        }
    }
}
