use nalgebra_glm::Vec3;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NavMeshAgent {
    pub current_path: Vec<Vec3>,
    pub current_waypoint_index: usize,
    pub target_position: Option<Vec3>,
    pub movement_speed: f32,
    pub arrival_threshold: f32,
    pub path_recalculation_threshold: f32,
    pub agent_radius: f32,
    pub agent_height: f32,
    pub current_triangle: Option<usize>,
    pub state: NavMeshAgentState,
    pub distance_to_destination: f32,
    pub avoidance_velocity: Vec3,
}

impl Default for NavMeshAgent {
    fn default() -> Self {
        Self {
            current_path: Vec::new(),
            current_waypoint_index: 0,
            target_position: None,
            movement_speed: 5.0,
            arrival_threshold: 0.3,
            path_recalculation_threshold: 2.0,
            agent_radius: 0.3,
            agent_height: 1.8,
            current_triangle: None,
            state: NavMeshAgentState::Idle,
            distance_to_destination: 0.0,
            avoidance_velocity: Vec3::zeros(),
        }
    }
}

impl NavMeshAgent {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_speed(mut self, speed: f32) -> Self {
        self.movement_speed = speed;
        self
    }

    pub fn with_radius(mut self, radius: f32) -> Self {
        self.agent_radius = radius;
        self
    }

    pub fn with_height(mut self, height: f32) -> Self {
        self.agent_height = height;
        self
    }

    pub fn with_arrival_threshold(mut self, threshold: f32) -> Self {
        self.arrival_threshold = threshold;
        self
    }

    pub fn set_destination(&mut self, destination: Vec3) {
        self.target_position = Some(destination);
        self.state = NavMeshAgentState::PathPending;
    }

    pub fn clear_destination(&mut self) {
        self.target_position = None;
        self.current_path.clear();
        self.current_waypoint_index = 0;
        self.state = NavMeshAgentState::Idle;
    }

    pub fn has_path(&self) -> bool {
        !self.current_path.is_empty()
    }

    pub fn is_moving(&self) -> bool {
        self.state == NavMeshAgentState::Moving
    }

    pub fn current_waypoint(&self) -> Option<Vec3> {
        self.current_path.get(self.current_waypoint_index).copied()
    }

    pub fn remaining_waypoints(&self) -> usize {
        if self.current_waypoint_index >= self.current_path.len() {
            0
        } else {
            self.current_path.len() - self.current_waypoint_index
        }
    }

    pub fn advance_waypoint(&mut self) -> bool {
        self.current_waypoint_index += 1;
        if self.current_waypoint_index >= self.current_path.len() {
            self.state = NavMeshAgentState::Arrived;
            true
        } else {
            false
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum NavMeshAgentState {
    #[default]
    Idle,
    PathPending,
    Moving,
    Arrived,
    NoPath,
}
