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

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

use crate::auth::Session;
use crate::db::DbConn;
use crate::messages::ChatBroadcaster;

pub mod auth;
pub mod cdn;
pub mod db;
pub mod llm;
pub mod messages;

#[get("/users", rank = 2)]
async fn users(_ag: Session, mut db: Connection<DbConn>) -> Json<Vec<i32>> {
    sqlx::query!("SELECT id FROM users")
        .fetch_all(&mut **db)
        .await
        .unwrap_or_else(|_| Vec::new())
        .into_iter()
        .map(|row| row.id)
        .collect::<Vec<i32>>()
        .into()
}

#[get("/users/<id>", rank = 1)]
async fn username_for_id(id: usize, _ag: Session, mut db: Connection<DbConn>) -> String {
    sqlx::query!("SELECT username FROM users WHERE id = $1", id as i32)
        .fetch_one(&mut **db)
        .await
        .map(|row| row.username)
        .unwrap_or_else(|_| "User not found".to_string())
}

#[launch]
fn rocket() -> Rocket<Build> {
    let chat = Arc::new(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(DbConn::init())
        .attach(Template::fairing())
        .mount("/static", FileServer::from("static"))
        .mount("/cdn", cdn::routes())
        .mount(
            "/",
            routes![
                favicon,
                messages::chat_page,
                auth::signup_page,
                auth::login_page,
                auth::mfa_page,
            ],
        )
        .mount(
            "/api",
            routes![
                messages::get_messages,
                messages::post_message,
                messages::event_stream,
                users,
                username_for_id,
                auth::signup,
                auth::login,
                auth::get_totp,
            ],
        )
}

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