//! Exponential backoff etcd connection.

#[cfg(all(feature = "distributed", feature = "self-heal"))]
use crate::error::{CypherError, CypherResult, ExecutionError};

/// Connect to etcd with exponential backoff retry.
///
/// Attempts up to `max_attempts` times, doubling the delay after each failure,
/// capped at 30 seconds. Returns the connected client on success or a
/// [`CypherError`] after all attempts are exhausted.
#[cfg(all(feature = "distributed", feature = "self-heal"))]
pub async fn connect_with_retry(
    endpoints: Vec<String>,
    max_attempts: usize,
) -> CypherResult<etcd_client::Client> {
    let mut delay = std::time::Duration::from_millis(250);
    let max_delay = std::time::Duration::from_secs(30);

    for attempt in 1..=max_attempts {
        match etcd_client::Client::connect(endpoints.clone(), None).await {
            Ok(c) => {
                tracing::info!(attempt, "etcd connected");
                return Ok(c);
            }
            Err(e) => {
                let last = attempt == max_attempts;
                tracing::warn!(
                    attempt,
                    error = %e,
                    backoff_ms = delay.as_millis(),
                    "etcd connect failed, retrying"
                );
                if last {
                    return Err(CypherError::Execution(ExecutionError::Internal(format!(
                        "etcd connect failed after {max_attempts} attempts: {e}"
                    ))));
                }
                tokio::time::sleep(delay).await;
                delay = (delay * 2).min(max_delay);
            }
        }
    }

    unreachable!()
}
