use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};

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

mod controllers;
mod sources;

fn routes() -> Router {
    Router::new()
        .route("/", get(controllers::home::get))
        .with_state(AppState::default())
}

#[derive(Default, Clone)]
pub struct AppState {
    get_cache: Arc<Mutex<HashMap<String, (OffsetDateTime, String)>>>,
}

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 static_dir = std::env::var("WARTHUNDER_LEAK_STATIC_DIR").unwrap_or("./static".to_string());

    let router = routes()
        .fallback_service(ServeDir::new(static_dir))
        .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};

    let log_filter = std::env::var("WARTHUNDER_LOG")
        .unwrap_or_else(|_| "warthunder_leak_counter=debug,warn".into());

    eprintln!("RUST_LOG: {log_filter}");

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