use std::env;
use crate::http_client::HttpClient;
use crate::api::{IpGeolocationApi, ReverseGeocodingApi, VerificationApi, NetworkEngineeringApi};
use crate::error::{Error, Result};

/// Official Rust client for BigDataCloud APIs.
///
/// Thread-safe — clone and share across threads freely.
///
/// # Example
/// ```no_run
/// use bigdatacloud::Client;
///
/// let client = Client::from_environment().unwrap();
/// let geo = client.ip_geolocation.get(Some("1.1.1.1"), "en").unwrap();
/// println!("{}, {}", geo.location.unwrap().city.unwrap_or_default(),
///                    geo.country.unwrap().name.unwrap_or_default());
/// ```
#[derive(Clone)]
pub struct Client {
    pub ip_geolocation: IpGeolocationApi,
    pub reverse_geocoding: ReverseGeocodingApi,
    pub verification: VerificationApi,
    pub network_engineering: NetworkEngineeringApi,
}

impl Client {
    /// Creates a client with the given API key.
    pub fn new(api_key: impl Into<String>) -> Result<Self> {
        let key = api_key.into();
        if key.trim().is_empty() {
            return Err(Error::Api {
                status_code: 0,
                endpoint: "Client::new".to_string(),
                body: "API key must not be empty".to_string(),
            });
        }
        let http = HttpClient::new(key);
        Ok(Self {
            ip_geolocation: IpGeolocationApi::new(http.clone()),
            reverse_geocoding: ReverseGeocodingApi::new(http.clone()),
            verification: VerificationApi::new(http.clone()),
            network_engineering: NetworkEngineeringApi::new(http),
        })
    }

    /// Creates a client reading the API key from the `BIGDATACLOUD_API_KEY` environment variable.
    pub fn from_environment() -> Result<Self> {
        let key = env::var("BIGDATACLOUD_API_KEY").map_err(|_| Error::Api {
            status_code: 0,
            endpoint: "Client::from_environment".to_string(),
            body: "BIGDATACLOUD_API_KEY environment variable is not set. \
                   Set it with: export BIGDATACLOUD_API_KEY=your-key-here".to_string(),
        })?;
        Self::new(key)
    }
}
