use crate::error::AppError;
use anyhow::anyhow;
use reqwest::Url;
use serde::de::DeserializeOwned;
use tracing::info;

#[derive(Clone)]
pub struct FinnhubClient {
    client: reqwest::Client,
    base_url: Url,
    api_token: String,
}

impl FinnhubClient {
    pub fn new(base_url: String, api_token: String) -> Result<Self, AppError> {
        // Ensure base_url ends with a slash for correct joining
        let base_url_str = if base_url.ends_with('/') {
            base_url
        } else {
            format!("{}/", base_url)
        };

        let url = Url::parse(&base_url_str)
            .map_err(|e| AppError::Configuration(format!("Invalid base URL: {}", e)))?;
        Ok(Self {
            client: reqwest::Client::builder()
                .timeout(std::time::Duration::from_secs(30))
                .build()
                .map_err(|e| AppError::Configuration(format!("Failed to create http client: {}", e)))?,
            base_url: url,
            api_token,
        })
    }

    pub async fn get<T: DeserializeOwned>(
        &self,
        endpoint: &str,
        params: Vec<(String, String)>,
    ) -> Result<T, AppError> {
        let mut url = self.base_url.join(endpoint).unwrap();
        url.query_pairs_mut()
            .extend_pairs(params.iter().map(|(k, v)| (k.as_str(), v.as_str())));
        url.query_pairs_mut()
            .append_pair("token", &self.api_token);

        info!("Sending Finnhub request to: {}", url);

        let res = self.client.get(url.clone()).send().await?;
        let status = res.status();
        
        if !status.is_success() {
            let error_text = res.text().await.unwrap_or_else(|_| "Unknown error".to_string());
            return Err(AppError::DataParsing(anyhow!(format!(
                "API request failed with status {}: {}",
                status,
                error_text
            ))));
        }

        let text = res.text().await?;
        info!("Received response from {}: {}", url, text);
        
        let json_res = serde_json::from_str::<T>(&text).map_err(|e| {
            AppError::DataParsing(anyhow!(format!("Failed to parse JSON from {}: {}. Body: {}", url, e, text)))
        })?;
        
        Ok(json_res)
    }
}


