use std::time::Duration;

use anyhow::Result;

/// HTTP Connectivity module for checking HTTP/HTTPS connections.
pub struct HttpConnector {
    timeout: Duration,
}

impl HttpConnector {
    /// Creates a new HTTP connector with the default configuration.
    pub fn new() -> Self {
        Self {
            timeout: Duration::from_secs(30),
        }
    }

    /// Creates a new HTTP connector with a custom timeout.
    pub fn with_timeout(timeout: Duration) -> Self {
        Self { timeout }
    }

    /// Checks if a URL is reachable.
    pub fn check_url(&self, url: &str) -> Result<bool> {
        let agent = ureq::Agent::new_with_config(
            ureq::Agent::config_builder()
                .timeout_global(Some(self.timeout))
                .build(),
        );

        match agent.head(url).call() {
            Ok(_) => Ok(true),
            Err(_) => Ok(false),
        }
    }

    /// Checks a URL and returns the status code if reachable.
    pub fn check_status(&self, url: &str) -> Result<Option<u16>> {
        let agent = ureq::Agent::new_with_config(
            ureq::Agent::config_builder()
                .timeout_global(Some(self.timeout))
                .build(),
        );

        match agent.head(url).call() {
            Ok(response) => Ok(Some(response.status().as_u16())),
            Err(_) => Ok(None),
        }
    }

    /// Gets the content of a URL.
    pub fn get_content(&self, url: &str) -> Result<String> {
        let agent = ureq::Agent::new_with_config(
            ureq::Agent::config_builder()
                .timeout_global(Some(self.timeout))
                .build(),
        );

        let mut response = agent.get(url).call()?;

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

        let content = response.body_mut().read_to_string()?;
        Ok(content)
    }

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

impl Default for HttpConnector {
    fn default() -> Self {
        Self::new()
    }
}
