use crate::entity::Entity;
use crate::math::{Vec2, Vec3, Ray, RaycastResult};
use crate::aim::{AimConfig, AimTarget};
use std::f32::consts::PI;

#[derive(Clone, Debug)]
pub struct BulletTracer {
    pub bullet_velocity: f32,
    pub bullet_mass: f32,
    pub gravity: f32,
    pub air_resistance: f32,
    pub drag_coefficient: f32,
    pub bullet_radius: f32,
    pub max_trace_distance: f32,
    pub max_prediction_ticks: u8,
}

impl Default for BulletTracer {
    fn default() -> Self {
        Self {
            bullet_velocity: 900.0,
            bullet_mass: 0.01,
            gravity: 9.8,
            air_resistance: 0.001,
            drag_coefficient: 0.295,
            bullet_radius: 0.005,
            max_trace_distance: 1000.0,
            max_prediction_ticks: 15,
        }
    }
}

impl BulletTracer {
    pub fn from_config(config: &AimConfig) -> Self {
        Self {
            bullet_velocity: config.bullet_velocity,
            gravity: config.bullet_gravity,
            max_trace_distance: config.max_distance,
            ..Self::default()
        }
    }

    fn predict_target_pos(&self, target: &Entity, ticks: u8) -> Vec3 {
        let tick_interval = 1.0 / 60.0;
        let time = ticks as f32 * tick_interval;
        target.pos + target.vel * time
    }

    fn calculate_flight_time(&self, start_pos: Vec3, end_pos: Vec3) -> f32 {
        let distance = (end_pos - start_pos).length();
        let base_time = distance / self.bullet_velocity;
        let vertical_distance = (end_pos.y - start_pos.y).abs();
        let gravity_time = (2.0 * vertical_distance / self.gravity).sqrt();
        base_time.max(gravity_time)
    }

    fn raycast(&self, start_pos: Vec3, end_pos: Vec3) -> Option<RaycastResult> {
        let ray = Ray::new(start_pos, (end_pos - start_pos).normalize());
        ray.cast(self.max_trace_distance, self.bullet_radius)
    }

    pub fn trace_bullet(
        &self,
        shooter_pos: Vec3,
        target: &Entity,
        config: &AimConfig,
    ) -> Option<AimTarget> {
        let distance = (target.pos - shooter_pos).length();
        if distance > self.max_trace_distance {
            return None;
        }

        let prediction_ticks = ((distance / self.bullet_velocity) * 60.0) as u8;
        let prediction_ticks = prediction_ticks.min(self.max_prediction_ticks);

        let predicted_pos = self.predict_target_pos(target, prediction_ticks);
        let flight_time = self.calculate_flight_time(shooter_pos, predicted_pos);
        let gravity_drop = 0.5 * self.gravity * flight_time * flight_time;
        let corrected_pos = Vec3::new(
            predicted_pos.x,
            predicted_pos.y - gravity_drop,
            predicted_pos.z,
        );

        let raycast_result = self.raycast(shooter_pos, corrected_pos);
        if let Some(result) = raycast_result {
            if result.entity_id == target.id {
                return Some(AimTarget {
                    entity_id: target.id,
                    head_pos: corrected_pos,
                    body_pos: target.pos,
                    distance,
                    fov: 0.0,
                    priority: 1.0,
                    visible: result.visible,
                    last_seen_time: 0.0,
                    prediction_ticks,
                });
            }
        }

        None
    }

    pub fn draw_trajectory(&self, start_pos: Vec3, end_pos: Vec3, color: [f32; 4]) {
    }
}

#[derive(Clone, Debug)]
pub struct RaycastResult {
    pub entity_id: u32,
    pub hit_pos: Vec3,
    pub normal: Vec3,
    pub distance: f32,
    pub visible: bool,
    pub obstacle_type: ObstacleType,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ObstacleType {
    None,
    Entity,
    Wall,
    Ground,
    Water,
    Glass,
}

#[derive(Clone, Debug)]
pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3,
}

impl Ray {
    pub fn new(origin: Vec3, direction: Vec3) -> Self {
        Self {
            origin,
            direction: direction.normalize(),
        }
    }

    pub fn cast(&self, max_distance: f32, radius: f32) -> Option<RaycastResult> {
        None
    }
}

impl Vec3 {
    pub fn length(&self) -> f32 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn normalize(&self) -> Self {
        let len = self.length();
        if len == 0.0 {
            return *self;
        }
        self / len
    }

    pub fn dot(&self, other: &Self) -> f32 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl std::ops::Sub for Vec3 {
    type Output = Self;
    fn sub(self, other: Self) -> Self::Output {
        Self {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        }
    }
}

impl std::ops::Add for Vec3 {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        Self {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl std::ops::Mul<f32> for Vec3 {
    type Output = Self;
    fn mul(self, scalar: f32) -> Self::Output {
        Self {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
        }
    }
}

impl std::ops::Div<f32> for Vec3 {
    type Output = Self;
    fn div(self, scalar: f32) -> Self::Output {
        Self {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
        }
    }
}



//禁止二改冷淡独家冷淡QQ群：849961629
//禁止二改冷淡独家冷淡QQ群：849961629
//禁止二改冷淡独家冷淡QQ群：849961629
//禁止二改冷淡独家冷淡QQ群：849961629
//禁止二改冷淡独家冷淡QQ群：849961629