use thiserror::Error;

/// Error type for OneIO operations.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum OneIoError {
    /// All IO-related errors (file system, EOF, etc.)
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    /// All network/remote operation errors (HTTP, FTP, S3, JSON parsing)
    #[error("{0}")]
    Network(Box<dyn std::error::Error + Send + Sync>),

    /// Network error with URL context for debugging
    #[error("{url}: {source}")]
    NetworkWithContext {
        source: Box<dyn std::error::Error + Send + Sync>,
        url: String,
    },

    /// Structured status errors from remote services
    #[error("{service} status error: {code}{}", .message.as_deref().map(|m| format!(": {m}")).unwrap_or_default())]
    Status {
        service: &'static str,
        code: u16,
        message: Option<String>,
    },

    /// Invalid header name or value
    #[error("Invalid header: {0}")]
    InvalidHeader(String),

    /// Invalid certificate data
    #[error("Invalid certificate: {0}")]
    InvalidCertificate(String),

    /// Feature not supported/compiled
    #[error("Not supported: {0}")]
    NotSupported(String),
}

// Convert various network-related errors to Network variant
#[cfg(feature = "http")]
impl From<reqwest::Error> for OneIoError {
    fn from(err: reqwest::Error) -> Self {
        OneIoError::Network(Box::new(err))
    }
}

#[cfg(feature = "ftp")]
impl From<suppaftp::FtpError> for OneIoError {
    fn from(err: suppaftp::FtpError) -> Self {
        OneIoError::Network(Box::new(err))
    }
}

#[cfg(feature = "json")]
impl From<serde_json::Error> for OneIoError {
    fn from(err: serde_json::Error) -> Self {
        OneIoError::Network(Box::new(err))
    }
}
