// src/main.rs
#[macro_use]
extern crate rocket;

use rocket::fs::{FileServer, NamedFile};
use rocket::http::Method;
use rocket::{Build, Rocket};
use rocket_cors::{AllowedOrigins, CorsOptions};
use rocket_db_pools::Database;
use rocket_dyn_templates::Template;
use std::env;
use std::sync::{Arc, LazyLock};

use crate::db::{Postgres, Redis};

pub mod auth;
pub mod cdn;
pub mod db;
pub mod handlers;
pub mod llm;
pub mod messenger;
pub mod user;

static LMSTUDIO_URL: LazyLock<String> =
    LazyLock::new(|| env::var("LMSTUDIO_URL").expect("Ensure LMSTUDIO_URL is set!"));

#[launch]
fn rocket() -> Rocket<Build> {
    // make sure the env is loaded
    dotenv::dotenv().expect("Failed to load env! aborting launch!");

    let chat = Arc::new(crate::messenger::ChatBroadcaster::new(32));

    let cors = CorsOptions::default()
        .allowed_origins(AllowedOrigins::all())
        .allowed_methods(
            vec![Method::Get, Method::Post, Method::Patch]
                .into_iter()
                .map(From::from)
                .collect(),
        )
        .allow_credentials(true);

    rocket::build()
        .manage(chat)
        .attach(cors.to_cors().unwrap())
        .attach(Postgres::init())
        .attach(Redis::init())
        .attach(Template::fairing())
        .mount("/static", FileServer::from("static"))
        .mount("/cdn", cdn::routes())
        .mount(
            "/",
            routes![
                favicon,
                messenger::chat_page,
                auth::signup_page,
                auth::login_page,
                auth::mfa_page,
                auth::invite_page,
            ],
        )
        .mount(
            "/api",
            routes![
                cdn::upload_profile_pic,
                messenger::post_message,
                messenger::event_stream,
                user::users,
                user::display_name,
                auth::signup,
                auth::login,
                auth::get_totp,
                auth::confirm_totp,
                auth::generate_invite,
                auth::verify_totp,
                auth::disable_totp,
                auth::get_totp_status,
                auth::change_password,
                auth::change_display_name,
                auth::change_username,
                auth::delete_account,
            ],
        )
        .register(
            "/",
            catchers![
                handlers::handle_404,
                handlers::handle_401,
                handlers::handle_default
            ],
        )
}

#[get("/favicon.ico")]
async fn favicon() -> NamedFile {
    NamedFile::open("static/favicon.ico").await.unwrap()
}
