pub mod route;

use std::sync::Arc;

use prometheus::{Encoder, TextEncoder};
use salvo::{affix_state, cors::Cors, handler, Router};

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

pub fn init(state: Arc<AppState>) -> Router {
    Router::new()
        .get(root)
        .push(Router::with_path("health").get(health))
        .push(Router::with_path("metrics").get(metrics))
        .push(router(state))
}

#[handler]
async fn root() -> &'static str {
    "☺ welcome to Rust app"
}

#[handler]
async fn health() -> &'static str {
    "ok"
}

#[handler]
async fn metrics() -> 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()
}

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

    Router::new()
        .hoop(affix_state::inject(state))
        .hoop(cors)
        .hoop(metric::Metric)
        .hoop(trace::Trace)
        .hoop(log::Log)
        .hoop(panic::Catch)
        .push(route::v1())
}
