use common::{grid::Grid, rtsim::ChunkResource};
use enum_map::EnumMap;
use serde::{Deserialize, Serialize};
use vek::*;
use world::World;

/// Represents the state of 'natural' elements of the world such as
/// plant/animal/resource populations, weather systems, etc.
///
/// Where possible, this data does not define the state of natural aspects of
/// the world, but instead defines 'modifications' that sit on top of the world
/// data generated by initial generation.
#[derive(Clone, Serialize, Deserialize)]
pub struct Nature {
    chunks: Grid<Chunk>,
}

impl Nature {
    pub fn generate(world: &World) -> Self {
        Self {
            chunks: Grid::populate_from(world.sim().get_size().map(|e| e as i32), |_| Chunk {
                res: EnumMap::<_, f32>::default().map(|_, _| 1.0),
            }),
        }
    }

    // TODO: Clean up this API a bit
    pub fn get_chunk_resources(&self, key: Vec2<i32>) -> EnumMap<ChunkResource, f32> {
        self.chunks.get(key).map(|c| c.res).unwrap_or_default()
    }

    pub fn set_chunk_resources(&mut self, key: Vec2<i32>, res: EnumMap<ChunkResource, f32>) {
        if let Some(chunk) = self.chunks.get_mut(key) {
            chunk.res = res;
        }
    }
}

#[derive(Clone, Serialize, Deserialize)]
pub struct Chunk {
    /// Represent the 'naturally occurring' resource proportion that exists in
    /// this chunk.
    ///
    /// 0.0 => None of the resources generated by terrain generation should be
    /// present
    ///
    /// 1.0 => All of the resources generated by terrain generation should be
    /// present
    ///
    /// It's important to understand this this number does not represent the
    /// total amount of a resource present in a chunk, nor is it even
    /// proportional to the amount of the resource present. To get the total
    /// amount of the resource in a chunk, one must first multiply this
    /// factor by the amount of 'natural' resources given by terrain
    /// generation. This value represents only the variable 'depletion' factor
    /// of that resource, which shall change over time as the world evolves
    /// and players interact with it.
    // TODO: Consider whether we can use `i16` or similar here instead: `f32` has more resolution
    // than we might need.
    #[serde(rename = "r")]
    #[serde(serialize_with = "crate::data::rugged_ser_enum_map::<_, _, _, 1>")]
    #[serde(deserialize_with = "crate::data::rugged_de_enum_map::<_, _, _, 1>")]
    res: EnumMap<ChunkResource, f32>,
}
