use axum::{Router, routing::get};

use crate::{
    MetricsApiError, blocks::METRICS_BLOCKS, gather_default_metrics, node::METRICS_NODE,
    p2p::METRICS_P2P, process::METRICS_PROCESS, transactions::METRICS_TX,
};

pub async fn start_prometheus_metrics_api(
    address: String,
    port: String,
) -> Result<(), MetricsApiError> {
    let app = Router::new()
        .route("/metrics", get(get_metrics))
        .route("/health", get("Service Up"));

    // Start the axum app
    let listener = tokio::net::TcpListener::bind(&format!("{address}:{port}")).await?;
    axum::serve(listener, app).await?;

    Ok(())
}

#[allow(unused_mut)]
pub(crate) async fn get_metrics() -> String {
    let mut ret_string = match METRICS_TX.gather_metrics() {
        Ok(string) => string,
        Err(_) => {
            tracing::error!("Failed to gather METRICS_TX");
            String::new()
        }
    };

    ret_string.push('\n');
    match gather_default_metrics() {
        Ok(string) => ret_string.push_str(&string),
        Err(_) => tracing::error!("Failed to gather default Prometheus metrics"),
    };

    ret_string.push('\n');
    match METRICS_BLOCKS.gather_metrics() {
        Ok(string) => ret_string.push_str(&string),
        Err(_) => tracing::error!("Failed to gather METRICS_BLOCKS"),
    };

    ret_string.push('\n');
    match METRICS_PROCESS.gather_metrics() {
        Ok(s) => ret_string.push_str(&s),
        Err(_) => tracing::error!("Failed to gather METRICS_PROCESS"),
    };

    ret_string.push('\n');
    match METRICS_P2P.gather_metrics() {
        Ok(s) => ret_string.push_str(&s),
        Err(_) => tracing::error!("Failed to gather METRICS_P2P"),
    };

    // METRICS_SYNC registers into the default Prometheus registry at init,
    // so its metrics are already included in gather_default_metrics() above.

    ret_string.push('\n');
    if let Some(node_metrics) = METRICS_NODE.get() {
        match node_metrics.gather_metrics() {
            Ok(s) => ret_string.push_str(&s),
            Err(_) => tracing::error!("Failed to gather METRICS_NODE"),
        };
    }

    ret_string
}
