use axum::{
    routing::post,
    // http::StatusCode,
    Router,
};

use log::{error, info, warn};

pub mod api;

use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    info(
        title = "Calcifer Server API",
        version = "1.0.0",
        description = "Calcifer Server API"
    ),
    paths(api::examples::single),
    components()
)]
pub(crate) struct ApiDoc;

/// Create OpenAPI 3.0 Specification File
pub fn generate_openapi_spec<T>(target: &str) -> Result<(), ()>
where
    T: OpenApi,
{
    // no_coverage: (R5) no way to make JSON export fail
    let output = T::openapi().to_pretty_json().map_err(|e| {
        error!("failed to export as JSON string: {e}");
    })?;

    std::fs::write(target, output).map_err(|e| {
        error!("failed to write to file: {e}");
    })
}

pub async fn rest_server() -> Result<(), ()> {
    // initialize tracing
    // tracing_subscriber::fmt::init();

    // build our application with a route
    info!("Building router...");
    let app = Router::new()
        .route("/examples/single", post(api::examples::single));

    info!("Starting listener...");
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3001")
        .await
        .map_err(|e| {
            error!("Failed to bind to port: {:?}", e);
        })?;

    info!("Serving...");
    axum::serve(
        listener,
        app.into_make_service_with_connect_info::<std::net::SocketAddr>()
    )
        .await
        .map_err(|e| {
            error!("Failed to serve: {:?}", e);
        })?;

    warn!("Server stopped");
    Ok(())
}
