use serde::{Deserialize, Serialize};

use crate::ecs::physics::components::{CharacterControllerComponent, ColliderShape};
use crate::ecs::physics::types::CharacterControllerConfig;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct SceneCharacterController {
    pub shape: SceneCharacterShape,
    pub max_speed: f32,
    pub acceleration: f32,
    pub jump_impulse: f32,
    pub crouch_enabled: bool,
    pub crouch_speed_multiplier: f32,
    pub sprint_speed_multiplier: f32,
    pub standing_half_height: f32,
    pub crouching_half_height: f32,
    pub scale: f32,
    pub config: SceneCharacterControllerConfig,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum SceneCharacterShape {
    Capsule { half_height: f32, radius: f32 },
    Ball { radius: f32 },
    Cuboid { hx: f32, hy: f32, hz: f32 },
}

impl Default for SceneCharacterShape {
    fn default() -> Self {
        Self::Capsule {
            half_height: 0.9,
            radius: 0.3,
        }
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(default)]
pub struct SceneCharacterControllerConfig {
    pub offset: f32,
    pub max_slope_climb_angle: f32,
    pub min_slope_slide_angle: f32,
    pub autostep_max_height: Option<f32>,
    pub autostep_min_width: Option<f32>,
    pub autostep_include_dynamic_bodies: bool,
    pub snap_to_ground: Option<f32>,
}

impl Default for SceneCharacterControllerConfig {
    fn default() -> Self {
        let config = CharacterControllerConfig::default();
        Self {
            offset: config.offset,
            max_slope_climb_angle: config.max_slope_climb_angle,
            min_slope_slide_angle: config.min_slope_slide_angle,
            autostep_max_height: config.autostep_max_height,
            autostep_min_width: config.autostep_min_width,
            autostep_include_dynamic_bodies: config.autostep_include_dynamic_bodies,
            snap_to_ground: config.snap_to_ground,
        }
    }
}

impl Default for SceneCharacterController {
    fn default() -> Self {
        Self {
            shape: SceneCharacterShape::default(),
            max_speed: 5.0,
            acceleration: 50.0,
            jump_impulse: 8.0,
            crouch_enabled: true,
            crouch_speed_multiplier: 0.5,
            sprint_speed_multiplier: 1.6,
            standing_half_height: 0.9,
            crouching_half_height: 0.45,
            scale: 1.0,
            config: SceneCharacterControllerConfig::default(),
        }
    }
}

impl From<&CharacterControllerComponent> for SceneCharacterController {
    fn from(controller: &CharacterControllerComponent) -> Self {
        Self {
            shape: match &controller.shape {
                ColliderShape::Capsule {
                    half_height,
                    radius,
                } => SceneCharacterShape::Capsule {
                    half_height: *half_height,
                    radius: *radius,
                },
                ColliderShape::Ball { radius } => SceneCharacterShape::Ball { radius: *radius },
                ColliderShape::Cuboid { hx, hy, hz } => SceneCharacterShape::Cuboid {
                    hx: *hx,
                    hy: *hy,
                    hz: *hz,
                },
                _ => SceneCharacterShape::default(),
            },
            max_speed: controller.max_speed,
            acceleration: controller.acceleration,
            jump_impulse: controller.jump_impulse,
            crouch_enabled: controller.crouch_enabled,
            crouch_speed_multiplier: controller.crouch_speed_multiplier,
            sprint_speed_multiplier: controller.sprint_speed_multiplier,
            standing_half_height: controller.standing_half_height,
            crouching_half_height: controller.crouching_half_height,
            scale: controller.scale,
            config: SceneCharacterControllerConfig {
                offset: controller.config.offset,
                max_slope_climb_angle: controller.config.max_slope_climb_angle,
                min_slope_slide_angle: controller.config.min_slope_slide_angle,
                autostep_max_height: controller.config.autostep_max_height,
                autostep_min_width: controller.config.autostep_min_width,
                autostep_include_dynamic_bodies: controller.config.autostep_include_dynamic_bodies,
                snap_to_ground: controller.config.snap_to_ground,
            },
        }
    }
}

impl SceneCharacterController {
    pub fn to_character_controller(&self) -> CharacterControllerComponent {
        CharacterControllerComponent {
            config: CharacterControllerConfig {
                offset: self.config.offset,
                max_slope_climb_angle: self.config.max_slope_climb_angle,
                min_slope_slide_angle: self.config.min_slope_slide_angle,
                autostep_max_height: self.config.autostep_max_height,
                autostep_min_width: self.config.autostep_min_width,
                autostep_include_dynamic_bodies: self.config.autostep_include_dynamic_bodies,
                snap_to_ground: self.config.snap_to_ground,
            },
            shape: match self.shape {
                SceneCharacterShape::Capsule {
                    half_height,
                    radius,
                } => ColliderShape::Capsule {
                    half_height,
                    radius,
                },
                SceneCharacterShape::Ball { radius } => ColliderShape::Ball { radius },
                SceneCharacterShape::Cuboid { hx, hy, hz } => ColliderShape::Cuboid { hx, hy, hz },
            },
            max_speed: self.max_speed,
            acceleration: self.acceleration,
            jump_impulse: self.jump_impulse,
            crouch_enabled: self.crouch_enabled,
            crouch_speed_multiplier: self.crouch_speed_multiplier,
            sprint_speed_multiplier: self.sprint_speed_multiplier,
            standing_half_height: self.standing_half_height,
            crouching_half_height: self.crouching_half_height,
            scale: self.scale,
            ..Default::default()
        }
    }
}
