use crate::coords::Range;

use super::ProjectionS;
use geo_macros::Prj;

#[derive(Prj)]
/// A struct representing the Mercator projection.
pub struct Mercator {
    /// The central longitude of the projection.
    pub central_lon: f64,
    /// The false easting of the projection.
    pub false_easting: f64,
    /// The false northing of the projection.
    pub false_northing: f64,
    /// The latitude of true scale of the projection.
    pub latitude_true_scale: f64,
}

fn proj_string<'a>(vs: Vec<(&'a str, &'a str)>) -> String {
    vs.into_iter()
        .map(|(option, value)| format!("+{}={}", option, value))
        .collect::<Vec<String>>()
        .join(" ")
}

impl Mercator {
    /// Creates a new instance of the `Mercator` projection with default values.
    pub fn new(
        central_lon: f64,
        false_easting: f64,
        false_northing: f64,
        latitude_true_scale: f64,
    ) -> Self {
        Self {
            central_lon,
            false_easting,
            false_northing,
            latitude_true_scale,
        }
    }
}

impl Default for Mercator {
    fn default() -> Self {
        Self {
            central_lon: 0.0,
            false_easting: 0.0,
            false_northing: 0.0,
            latitude_true_scale: 0.0,
        }
    }
}

impl ProjectionS for Mercator {
    fn build(&self) -> String {
        let _central_lon = format!("{:.1}", &self.central_lon);
        let _false_easting = format!("{:.1}", &self.false_easting);
        let _false_northing = format!("{:.1}", &self.false_northing);
        let _ts = format!("{:.1}", &self.latitude_true_scale);

        let input = vec![
            ("proj", "merc"),
            ("lon_0", _central_lon.as_str()),
            ("x_0", _false_easting.as_str()),
            ("y_0", _false_northing.as_str()),
            ("lat_ts", _ts.as_str()),
            ("units", "m"),
            ("ellps", "GRS80"),
        ];
        let _proj_string = proj_string(input);
        _proj_string
    }
}
