#[macro_use]
extern crate rocket;

use std::env;
use std::path::PathBuf;

use auth::session;
use db::migrate::run_migrations;
use db::schema::DollTags;
use rocket::fairing::AdHoc;
use rocket::fs::{relative, FileServer};
use rocket_db_pools::Database;
use routes::form::accounts;
use routes::{account, admin, error_handlers, form, public};

pub mod auth;
pub mod db;
pub mod ids;
pub mod pages;
pub mod routes;

#[launch]
fn rocket() -> _ {
	// in dev., this is easy to get right, but in prod in special systems such as nixos, it's annoying to predict.
	// instead, we can simply set it at runtime.
	// Priority order:
	// 1. environment variable
	// 2. `[..]/bin/dolltags/../lib/assets` (folder containing `/bin/dolltags` and `/lib/assets`)
	// 3. `/assets` relative to cargo manifest (dev env)
	let assets_path = env::var("ASSETS_PATH")
		.map(|v| PathBuf::from(v))
		.ok()
		.or_else(|| {
			env::current_exe().ok().and_then(|path| {
				// path = /bin/dolltags
				// path.parent.parent = /
				let assets_dir = path.parent()?.parent()?.join("lib/assets");
				if assets_dir.exists() {
					Some(assets_dir)
				} else {
					None
				}
			})
		})
		.unwrap_or_else(|| PathBuf::from(relative!("/assets")));

	rocket::build()
		.attach(pages::init_templates())
		.attach(DollTags::init())
		.attach(AdHoc::try_on_ignite("SQLx migrations", run_migrations))
		.register(
			"/",
			catchers![
				error_handlers::not_found,
				session::unauthorized,
				session::forbidden
			],
		)
		.mount("/assets", FileServer::from(assets_path))
		.mount(
			"/account",
			routes![
				account::index,
				account::show_settings,
				account::change_settings,
				account::change_password,
				form::register_tag::show_register,
				form::register_tag::handle_register,
				form::register_tag::show_edit_tag,
				form::register_tag::handle_edit_tag,
				account::ask_delete,
				account::confirm_delete,
				account::ask_terminate_account,
				account::confirm_terminate_account,
				account::export_data,
			],
		)
		.mount("/admin", routes![admin::index,])
		.mount(
			"/",
			routes![
				public::index,
				public::short_url,
				public::show_profile,
				accounts::show_register,
				accounts::handle_register,
				accounts::show_login,
				accounts::handle_login,
				accounts::logout,
			],
		)
}
