use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
    routing::get,
    Router,
};

use std::net::SocketAddr;
use std::str::FromStr;

#[tokio::main]
async fn main() {
    let mut listen = String::from("[::]:9152");
    let mut args = std::env::args();
    args.next();
    loop {
        let arg = if let Some(arg) = args.next() {
            arg
        } else {
            break;
        };

        match arg.as_str() {
            "--help" | "-h" => {
                println!("Prometheus exporter for NixOS systems");
                println!("Use --listen <addr:port> bind the web service.");
                println!("Output will be on /metrics endpoint. HTTP 500 if something broke while scraping.");
                std::process::exit(0);
            }
            "--listen" => {
                listen = args.next().unwrap();
            }
            unknown => {
                println!("unknown option: {}", unknown);
                std::process::exit(1)
            }
        }
    }

    let app = Router::new().route("/metrics", get(metrics));

    let addr = SocketAddr::from_str(&listen).unwrap();
    println!("listening on http://{}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

fn get_current_system() -> Result<(String, String), String> {
    let symlink = match std::fs::read_link("/run/current-system") {
        Ok(symlink) => symlink,
        Err(err) => return Err(err.to_string()),
    };

    let (hash, name) = symlink
        .file_name()
        .ok_or_else(String::default)?
        .to_str()
        .ok_or_else(String::default)?
        .split_once("-")
        .ok_or_else(String::default)?;

    Ok((String::from(hash), String::from(name)))
}

async fn metrics() -> Response {
    let current_system = get_current_system();
    let (hash, name) = match current_system {
        Ok((hash, name)) => (hash, name),
        Err(err) => {
            println!("failed: {}", err);
            return (StatusCode::INTERNAL_SERVER_ERROR, "").into_response();
        }
    };

    (
    StatusCode::OK,
    format!("nixos_current_system_hash{{hash=\"{}\"}} 1\nnixos_current_system_name{{name=\"{}\"}} 1\n", hash, name)
  ).into_response()
}