use std::fmt;

use crate::error::{ErrorCode, KErr};

#[derive(Debug)]
pub enum NetworkError {
    Connection,                                              // Could not connect (DNS failure, refused)
    Timeout,                                                 // Request exceeded timeout
    RequestFailed(Box<dyn std::error::Error + Send + Sync>), // All other errors: HTTP, TLS, parsing, etc.
}

impl fmt::Display for NetworkError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            NetworkError::Connection => write!(f, "Could not connect to server"),
            NetworkError::Timeout => write!(f, "Request timed out"),
            NetworkError::RequestFailed(err) => write!(f, "Request failed: {}", err),
        }
    }
}

impl From<NetworkError> for KErr {
    fn from(value: NetworkError) -> Self {
        KErr::new(ErrorCode::Network, value.to_string())
    }
}

#[cfg(test)]
mod tests {
    use crate::utils::string_error::StringError;

    use super::*;
    use rstest::rstest;

    #[rstest]
    #[case(NetworkError::Connection, "Could not connect to server")]
    #[case(NetworkError::Timeout, "Request timed out")]
    #[case(NetworkError::RequestFailed(Box::new(StringError("Something went wrong".into()))),
           "Request failed: Something went wrong")]
    fn network_error_to_string(#[case] network_error: NetworkError, #[case] expected: &str) {
        assert_eq!(network_error.to_string(), expected);
    }

    #[rstest]
    #[case(NetworkError::Connection, "Could not connect to server")]
    #[case(NetworkError::Timeout, "Request timed out")]
    #[case(NetworkError::RequestFailed("HTTP 500".into()), "Request failed: HTTP 500")]
    fn network_error_into_kameleoon_error(#[case] network_error: NetworkError, #[case] expected_message: &str) {
        let kam_err: KErr = network_error.into();

        assert!(matches!(kam_err.code(), ErrorCode::Network));
        assert_eq!(kam_err.message(), expected_message);
    }
}
