use nalgebra_glm::{Vec2, Vec3};

#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum GrassDomain {
    Finite { center: Vec2, half_extents: Vec2 },
    Infinite,
}

#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct GrassTypeParams {
    pub height_min: f32,
    pub height_max: f32,
    pub width: f32,
    pub density: f32,
    pub tilt_min: f32,
    pub tilt_max: f32,
    pub bend_min: f32,
    pub bend_max: f32,
    pub color_base: [f32; 4],
    pub color_tip: [f32; 4],
    pub gloss: f32,
    pub wind_response: f32,
    pub clump_height_variance: f32,
    pub clump_pull: f32,
    pub clump_face_away: f32,
    pub vertex_distribution: f32,
}

impl Default for GrassTypeParams {
    fn default() -> Self {
        Self {
            height_min: 0.55,
            height_max: 1.0,
            width: 0.075,
            density: 1.0,
            tilt_min: 0.3,
            tilt_max: 0.9,
            bend_min: 0.5,
            bend_max: 1.0,
            color_base: [0.02, 0.09, 0.015, 1.0],
            color_tip: [0.13, 0.28, 0.05, 1.0],
            gloss: 0.5,
            wind_response: 1.0,
            clump_height_variance: 0.15,
            clump_pull: 0.12,
            clump_face_away: 0.35,
            vertex_distribution: 1.0,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct GrassPusher {
    pub position: Vec3,
    pub radius: f32,
    pub strength: f32,
}

#[derive(Clone, Debug, PartialEq)]
pub struct GrassHeightMap {
    pub origin: Vec2,
    pub world_span: f32,
    pub resolution: u32,
    pub heights: Vec<f32>,
    pub height_min: f32,
    pub height_max: f32,
    pub revision: u64,
}

#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(default)]
pub struct GrassSettings {
    pub enabled: bool,
    pub domain: GrassDomain,
    pub ground_height: f32,
    pub high_radius: f32,
    pub low_radius: f32,
    pub far_radius: f32,
    pub type_noise_scale: f32,
    pub clump_scale: f32,
    pub types: Vec<GrassTypeParams>,
    #[serde(skip)]
    pub types_revision: u64,
    #[serde(skip)]
    pub pushers: Vec<GrassPusher>,
    #[serde(skip)]
    pub height_map: Option<GrassHeightMap>,
}

impl Default for GrassSettings {
    fn default() -> Self {
        Self {
            enabled: false,
            domain: GrassDomain::Finite {
                center: Vec2::new(0.0, 0.0),
                half_extents: Vec2::new(25.0, 25.0),
            },
            ground_height: 0.0,
            high_radius: 40.0,
            low_radius: 120.0,
            far_radius: 600.0,
            type_noise_scale: 36.0,
            clump_scale: 1.7,
            types: vec![GrassTypeParams::default()],
            types_revision: 1,
            pushers: Vec::new(),
            height_map: None,
        }
    }
}

impl GrassTypeParams {
    pub fn meadow() -> Self {
        Self::default()
    }

    pub fn dry() -> Self {
        Self {
            height_min: 0.4,
            height_max: 0.75,
            width: 0.06,
            tilt_min: 0.4,
            tilt_max: 1.0,
            bend_min: 0.4,
            bend_max: 0.9,
            color_base: [0.04, 0.10, 0.02, 1.0],
            color_tip: [0.25, 0.22, 0.06, 1.0],
            gloss: 0.4,
            wind_response: 1.25,
            clump_height_variance: 0.18,
            clump_pull: 0.08,
            clump_face_away: 0.5,
            vertex_distribution: 1.1,
            ..Self::default()
        }
    }

    pub fn flowers() -> Self {
        Self {
            height_min: 0.35,
            height_max: 0.65,
            width: 0.075,
            tilt_min: 0.25,
            tilt_max: 0.7,
            bend_min: 0.4,
            bend_max: 0.8,
            color_base: [0.03, 0.10, 0.02, 1.0],
            color_tip: [0.35, 0.18, 0.18, 1.0],
            gloss: 0.45,
            wind_response: 0.8,
            clump_height_variance: 0.12,
            clump_pull: 0.15,
            clump_face_away: 0.25,
            vertex_distribution: 0.9,
            ..Self::default()
        }
    }
}
