mod prelude;
use prelude::*;
mod routes;
mod templates;

use std::net::SocketAddr;
use std::sync::Arc;

use axum::handler::HandlerWithoutStateExt;
use std::error::Error;
use tokio::net::TcpListener;

fn migrate(connection: &mut rusqlite::Connection) -> Result<()> {
	Ok(())
}

fn init(connection: &mut rusqlite::Connection) -> rusqlite::Result<()> {
	Ok(())
}

async fn serve(dbs: DbS, router: Arc<Router>, req: Request) -> Response {
	let method = req.method().as_str();
	let uri = format!("{}", req.uri());

	let (handler, path_params) = match router.get(method, &uri) {
		Ok(h) => h,
		Err(sc) => {
			return (http::status::StatusCode::from_u16(sc).unwrap(), "")
				.into_response()
		},
	};

	handler(req, RequestCtx { dbs, path_params }).await
}

async fn go() -> Result<()> {
	let mut conn = rusqlite::Connection::open("./shelves.db")?;
	migrate(&mut conn)?;

	let (tx, _, _) =
		atelier::rusqlite_thread_pool::spawn_threadpool_supervised(
			4,
			"./shelves.db",
			|conn| init(conn),
		)?;

	let addr = "127.0.0.1:8333".parse::<SocketAddr>()?;
	let listener = TcpListener::bind(addr).await?;

	let router = Arc::new(routes::make_router());
	let s = move |req: Request| {
		let tx = tx.clone();
		let router = router.clone();

		serve(tx, router.clone(), req)
	};

	axum::serve(listener, s.into_make_service()).await?;

	Ok(())
}

fn main() {
	let rt = tokio::runtime::Builder::new_multi_thread()
		.enable_all()
		.build()
		.unwrap();

	rt.block_on(go()).unwrap();
}
