use crate::model::{
    role::Role,
    user::{SchnupperBetreuerUser, User, UserWithRoles},
};
use futures::future::join_all;
use rocket::{
    get,
    http::Status,
    request::{FlashMessage, FromRequest, Outcome},
    routes, Request, Route, State,
};
use rocket_dyn_templates::{tera::Context, Template};
use sqlx::SqlitePool;

// Custom request guard to extract the Referer header
struct Referer(String);

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Referer {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        match request.headers().get_one("Referer") {
            Some(referer) => Outcome::Success(Referer(referer.to_string())),
            None => Outcome::Error((Status::BadRequest, ())),
        }
    }
}

#[get("/schnupper")]
async fn index(
    db: &State<SqlitePool>,
    user: SchnupperBetreuerUser,
    flash: Option<FlashMessage<'_>>,
) -> Template {
    let schnupperant = Role::find_by_name(db, "schnupperant").await.unwrap();

    let user_futures: Vec<_> = User::all_with_role(db, &schnupperant)
        .await
        .into_iter()
        .map(|u| async move { UserWithRoles::from_user(u, db).await })
        .collect();
    let users: Vec<UserWithRoles> = join_all(user_futures).await;

    let mut context = Context::new();
    if let Some(msg) = flash {
        context.insert("flash", &msg.into_inner());
    }
    context.insert("schnupperanten", &users);
    context.insert(
        "loggedin_user",
        &UserWithRoles::from_user(user.into(), db).await,
    );

    Template::render("admin/schnupper/index", context.into_json())
}

pub fn routes() -> Vec<Route> {
    routes![index]
}
