use crate::physics::orbit::MERCURY_RADIUS;
use crate::terrain::heightmap::Heightmap;

pub struct ElevationGrid {
    pub rows: usize,
    pub cols: usize,
    pub lat_min: f64,
    pub lat_max: f64,
    pub lon_min: f64,
    pub lon_max: f64,
    pub data: Vec<f64>,
}

impl ElevationGrid {
    pub fn generate(
        lat_min: f64,
        lat_max: f64,
        lon_min: f64,
        lon_max: f64,
        rows: usize,
        cols: usize,
    ) -> Self {
        let hmap = Heightmap::new(2048);
        let mut data = Vec::with_capacity(rows * cols);
        for r in 0..rows {
            let lat = lat_min + (r as f64 / (rows - 1).max(1) as f64) * (lat_max - lat_min);
            for c in 0..cols {
                let lon = lon_min + (c as f64 / (cols - 1).max(1) as f64) * (lon_max - lon_min);
                data.push(hmap.sample(lat, lon));
            }
        }
        Self {
            rows,
            cols,
            lat_min,
            lat_max,
            lon_min,
            lon_max,
            data,
        }
    }

    pub fn get(&self, row: usize, col: usize) -> f64 {
        self.data[row * self.cols + col]
    }

    pub fn min_elevation(&self) -> f64 {
        self.data.iter().cloned().fold(f64::INFINITY, f64::min)
    }

    pub fn max_elevation(&self) -> f64 {
        self.data.iter().cloned().fold(f64::NEG_INFINITY, f64::max)
    }

    pub fn mean_elevation(&self) -> f64 {
        self.data.iter().sum::<f64>() / self.data.len() as f64
    }
}

pub fn elevation(lat: f64, lon: f64) -> f64 {
    let hmap = Heightmap::new(2048);
    hmap.sample(lat, lon)
}

pub fn radius_at(lat: f64, lon: f64) -> f64 {
    MERCURY_RADIUS + elevation(lat, lon)
}
