use crate::error::{CommonResult as Result, CommonError as Error};

/// Retry function with exponential backoff
pub async fn retry_with_backoff<F, T, E>(
    mut f: F,
    max_retries: u32,
    base_delay: u64,
) -> Result<T>
where
    F: FnMut() -> std::result::Result<T, E>,
    E: std::fmt::Display,
{
    let mut last_error = None;
    
    for attempt in 0..=max_retries {
        match f() {
            Ok(result) => return Ok(result),
            Err(e) => {
                last_error = Some(e.to_string());
                if attempt < max_retries {
                    let delay = base_delay * 2_u64.pow(attempt);
                    tokio::time::sleep(tokio::time::Duration::from_millis(delay)).await;
                }
            }
        }
    }
    
    Err(Error::InternalError(format!(
        "Operation failed after {} retries: {}",
        max_retries,
        last_error.unwrap()
    )))
}

/// Timeout wrapper for async operations
pub async fn with_timeout<F, T>(
    future: F,
    timeout_duration: std::time::Duration,
) -> Result<T>
where
    F: std::future::Future<Output = Result<T>>,
{
    tokio::time::timeout(timeout_duration, future)
        .await
        .map_err(|_| Error::IoError("Operation timed out".to_string()))?
}
