use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub enum NoiseType {
    #[default]
    Perlin,
    Simplex,
    Billow,
    RidgedMulti,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct NoiseConfig {
    pub seed: u32,
    pub frequency: f64,
    pub octaves: usize,
    pub lacunarity: f64,
    pub persistence: f64,
    pub noise_type: NoiseType,
}

impl Default for NoiseConfig {
    fn default() -> Self {
        Self {
            seed: 0,
            frequency: 0.02,
            octaves: 4,
            lacunarity: 2.0,
            persistence: 0.5,
            noise_type: NoiseType::Perlin,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerrainConfig {
    pub width: f32,
    pub depth: f32,
    pub resolution_x: u32,
    pub resolution_z: u32,
    pub height_scale: f32,
    pub noise: NoiseConfig,
    pub uv_scale: [f32; 2],
}

impl Default for TerrainConfig {
    fn default() -> Self {
        Self {
            width: 100.0,
            depth: 100.0,
            resolution_x: 64,
            resolution_z: 64,
            height_scale: 10.0,
            noise: NoiseConfig::default(),
            uv_scale: [1.0, 1.0],
        }
    }
}

impl TerrainConfig {
    pub fn new(width: f32, depth: f32, resolution_x: u32, resolution_z: u32) -> Self {
        Self {
            width,
            depth,
            resolution_x,
            resolution_z,
            ..Default::default()
        }
    }

    pub fn with_height_scale(mut self, height_scale: f32) -> Self {
        self.height_scale = height_scale;
        self
    }

    pub fn with_noise(mut self, noise: NoiseConfig) -> Self {
        self.noise = noise;
        self
    }

    pub fn with_uv_scale(mut self, uv_scale: [f32; 2]) -> Self {
        self.uv_scale = uv_scale;
        self
    }

    pub fn with_seed(mut self, seed: u32) -> Self {
        self.noise.seed = seed;
        self
    }

    pub fn with_frequency(mut self, frequency: f64) -> Self {
        self.noise.frequency = frequency;
        self
    }

    pub fn with_octaves(mut self, octaves: usize) -> Self {
        self.noise.octaves = octaves;
        self
    }
}
