use std::{future::Future, pin::Pin};

use anyhow::Result;
use axum::{routing::get, Router};
use tokio::net::TcpListener;
use tower_http::services::ServeDir;

mod controllers;
mod sources;

fn routes() -> Router {
    Router::new()
        .route("/", get(controllers::home::get))
        .fallback_service(ServeDir::new("./static"))
}

pub struct Config {
    pub port: u16,
}

pub struct RunningServer {
    pub port: u16,
    pub server: Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>>,
}

pub async fn run(config: Config) -> Result<RunningServer> {
    setup_tracing();

    let router = routes().layer(tower_http::trace::TraceLayer::new_for_http());

    let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", config.port)).await?;

    let port = tcp_listener.local_addr()?.port();

    tracing::info!("Listening on http://localhost:{port}");
    let server = Box::pin(async move {
        axum::serve(tcp_listener, router).await?;
        Ok(())
    });

    Ok(RunningServer { port, server })
}

pub fn setup_tracing() {
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

    tracing_subscriber::registry()
        .with(tracing_subscriber::fmt::layer())
        .try_init()
        .ok();
}
