use super::{Lat, Lon, Range};
use proj::Proj;
use proj5;
use thiserror::Error;
mod mercator;

pub use mercator::Mercator;

#[derive(Debug, Clone, Copy)]
pub enum Projs {
    PlateCarree,
    LambertConformal,
    LambertCylindrical,
    Mercator,
}

/// A trait for defining a projection.
pub trait ProjectionS {
    /// Returns a proj-string of the projection.
    fn build(&self) -> String;
}

#[derive(Debug, Error)]
pub(super) enum ProjError {
    #[error("proj error")]
    ProjError(#[from] proj::ProjError),
}

// pub(super) struct PCS<T: ProjectionS> {
//     pub lon_range: Range,
//     pub lat_range: Range,
//     pub proj_param: T,
//     // pub proj_target: proj5::CoordinateBuf,
//     pub transformer: Proj,
// }

// impl<T: ProjectionS> PCS<T> {
//     pub(super) fn new(proj_param: T, lon_range: Option<Range>, lat_range: Option<Range>) -> Self {
//         let (lon_range, lat_range) = proj_param.logic_range(lon_range, lat_range);
//         Self {
//             lon_range,
//             lat_range,
//             transformer: Proj::new(proj_param.build().as_str()).unwrap(),
//             proj_param: proj_param,
//         }
//     }

//     pub fn bbox(&self) -> Result<(Range, Range), ProjError> {
//         let _proj_transformer = &self.transformer;
//         let lb = (self.lon_range.0.to_radians(), self.lat_range.0.to_radians());
//         let rt = (self.lon_range.1.to_radians(), self.lat_range.1.to_radians());

//         let bl = _proj_transformer.convert(lb)?;
//         let rt = _proj_transformer.convert(rt)?;

//         Ok((Range::from((bl.0, rt.0)), Range::from((bl.1, rt.1))))
//     }

//     pub fn map(&self, lon_lat: (Lat, Lon)) -> (f64, f64) {
//         let _proj_transformer = &self.transformer;
//         let _lon_lat = _proj_transformer
//             .convert((lon_lat.0.to_radians(), lon_lat.1.to_radians()))
//             .unwrap();

//         _lon_lat
//     }
// }
