use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use lettre::{SmtpTransport, Transport};
use serde::Deserialize;
use sqlx::PgPool;

use crate::{
    models::{Function, Registration, Role, User},
    utils::{email, ApplicationError},
};

#[derive(Deserialize)]
pub struct NewUserForm {
    email: String,
    name: String,
    role: u8,
    function: u8,
    area: Option<i32>,
}

#[actix_web::post("/users/new")]
pub async fn post_new(
    user: web::ReqData<User>,
    pool: web::Data<PgPool>,
    form: web::Form<NewUserForm>,
    mailer: web::Data<SmtpTransport>,
) -> Result<impl Responder, ApplicationError> {
    if user.role != Role::AreaManager && user.role != Role::Admin {
        return Err(ApplicationError::Unauthorized);
    }

    let mut area_id = user.area_id;

    if user.role == Role::Admin && form.area.is_some() {
        area_id = form.area.unwrap();
    }

    let role = Role::try_from(form.role)?;
    let function = Function::try_from(form.function)?;

    let id = User::create(
        pool.get_ref(),
        &form.name,
        &form.email,
        role,
        function,
        area_id,
    )
    .await?;

    let registration = Registration::insert_new_for_user(pool.get_ref(), id).await?;
    let new_user = User::read_by_id(pool.get_ref(), id).await?.unwrap();
    let message = email::build_registration_message(&new_user, &registration.token)?;

    mailer.send(&message)?;

    Ok(HttpResponse::Found()
        .insert_header((LOCATION, "/users"))
        .finish())
}
