use std::{net::SocketAddr, sync::Arc};

use felicia::{config::AppConfig, startup};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt::init();

    let config = Arc::new(AppConfig::new()?);
    let app = startup::create_app(config.clone()).await?;

    let addr = SocketAddr::from(([0, 0, 0, 0], config.port()));

    tracing::info!("service up and running at {addr}");

    #[cfg(unix)]
    {
        use tokio::signal::{self, unix::SignalKind};

        let mut sigterm = signal::unix::signal(SignalKind::terminate())?;
        let mut sigint = signal::unix::signal(SignalKind::interrupt())?;
        axum::Server::bind(&addr)
            .serve(app.into_make_service())
            .with_graceful_shutdown(async move {
                tokio::select! {
                    _ = signal::ctrl_c() => tracing::warn!("terminating by keyboard interrupt"),
                    _ = sigint.recv() => tracing::warn!("terminating by SIGINT"),
                    _ = sigterm.recv() => tracing::warn!("terminating by SIGTERM")
                }
            })
            .await?;
    }

    #[cfg(not(unix))]
    {
        axum::Server::bind(&addr)
            .serve(app.into_make_service())
            .with_graceful_shutdown(async move {
                let _ = tokio::signal::ctrl_c().await;
            })
            .await?;
    }

    Ok(())
}
