pub mod route;

use std::sync::Arc;

use axum::{routing::get, Router};
use prometheus::{Encoder, TextEncoder};
use tower_http::cors::CorsLayer;

use infra::{
    self,
    core::AppState,
    middleware::{
        log, metric, panic,
        trace::{self, TRACE_ID},
    },
};

pub fn init() -> Router<Arc<AppState>> {
    // 路由组册
    Router::new()
        .route("/", get(|| async { "☺ welcome to Rust app" }))
        .route("/health", get(health))
        .route("/metrics", get(metric))
        .merge(router())
}

async fn health() -> &'static str {
    "ok"
}

async fn metric() -> String {
    let encoder = TextEncoder::new();
    let metric_families = prometheus::gather();

    let mut buffer = Vec::new();
    encoder.encode(&metric_families, &mut buffer).unwrap();

    String::from_utf8(buffer).unwrap()
}

fn router() -> Router<Arc<AppState>> {
    let cors = CorsLayer::permissive().expose_headers(vec![TRACE_ID]);

    Router::new()
        .nest("/v1", route::v1())
        .layer(axum::middleware::from_fn(panic::catch_mw))
        .layer(axum::middleware::from_fn(log::log_mw))
        .layer(axum::middleware::from_fn(trace::trace_mw))
        .layer(axum::middleware::from_fn(metric::metric_mw))
        .layer(cors)
}
