use std::time::Duration;

use anyhow::Result;
use reqwest::{Client, StatusCode, Url};

/// HTTP Connectivity module for checking HTTP/HTTPS connections
pub struct HttpConnector {
    client: Client,
}

impl HttpConnector {
    /// Create a new HTTP connector with the default configuration
    pub fn new() -> Result<Self> {
        let client = Client::builder().timeout(Duration::from_secs(30)).build()?;

        Ok(Self { client })
    }

    /// Create a new HTTP connector with a custom timeout
    pub fn with_timeout(timeout: Duration) -> Result<Self> {
        let client = Client::builder().timeout(timeout).build()?;

        Ok(Self { client })
    }

    /// Check if a URL is reachable
    pub async fn check_url<U: AsRef<str>>(&self, url: U) -> Result<bool> {
        let url_str = url.as_ref();
        let url = Url::parse(url_str)?;

        let result = self.client.head(url).send().await;

        Ok(result.is_ok())
    }

    /// Check a URL and return the status code if reachable
    pub async fn check_status<U: AsRef<str>>(&self, url: U) -> Result<Option<StatusCode>> {
        let url_str = url.as_ref();
        let url = Url::parse(url_str)?;

        let result = self.client.head(url).send().await;

        match result {
            Ok(response) => Ok(Some(response.status())),
            Err(_) => Ok(None),
        }
    }

    /// Get the content of a URL
    pub async fn get_content<U: AsRef<str>>(&self, url: U) -> Result<String> {
        let url_str = url.as_ref();
        let url = Url::parse(url_str)?;

        let response = self.client.get(url).send().await?;

        if !response.status().is_success() {
            return Err(anyhow::anyhow!(
                "HTTP request failed with status: {}",
                response.status()
            ));
        }

        let content = response.text().await?;
        Ok(content)
    }

    /// Verify that a URL responds with a specific status code
    pub async fn verify_status<U: AsRef<str>>(
        &self,
        url: U,
        expected_status: StatusCode,
    ) -> Result<bool> {
        match self.check_status(url).await? {
            Some(status) => Ok(status == expected_status),
            None => Ok(false),
        }
    }
}

impl Default for HttpConnector {
    fn default() -> Self {
        Self::new().expect("Failed to create default HttpConnector")
    }
}
