use std::{fmt::Display, future::Future, time::Instant};

use tracing::Instrument;

use crate::observability::{MetricsRegistry, SqlMetricLabels};

/// Observes one SQL query future without recording SQL text or parameter values.
pub async fn observe_sql_query<T, E, Fut>(
    metrics: Option<&MetricsRegistry>,
    db_kind: &str,
    repository: &str,
    method: &str,
    operation: &str,
    future: Fut,
) -> Result<T, E>
where
    E: Display,
    Fut: Future<Output = Result<T, E>>,
{
    let started = Instant::now();
    let span = tracing::debug_span!(
        "rs_zero.sql.query",
        db_kind = db_kind,
        repository = repository,
        method = method,
        operation = operation,
        result = tracing::field::Empty
    );
    let result = future.instrument(span.clone()).await;
    let result_label = if result.is_ok() { "success" } else { "error" };
    span.record("result", tracing::field::display(result_label));
    if let Some(metrics) = metrics {
        metrics.record_sql_query(
            SqlMetricLabels::new(db_kind, repository, method, operation, result_label),
            started.elapsed(),
        );
    }
    result
}
