use actix_identity::Identity;
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use serde::Deserialize;
use sqlx::PgPool;

use crate::{
    endpoints::IdPath,
    models::{Function, Role, User},
};

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

#[actix_web::post("/users/edit/{id}")]
pub async fn post_edit(
    user: Identity,
    pool: web::Data<PgPool>,
    path: web::Path<IdPath>,
    form: web::Form<EditUserForm>,
) -> impl Responder {
    // TODO: rewrite
    let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
        .await
        .unwrap().unwrap();

    if current_user.role != Role::AreaManager && current_user.role != Role::Admin {
        return HttpResponse::Unauthorized().finish();
    }

    if let Some(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await.unwrap() {
        if current_user.role == Role::AreaManager && current_user.area_id != user_in_db.area_id {
            return HttpResponse::Unauthorized().finish();
        }

        let mut changed = false;

        let email = if user_in_db.email != form.email {
            changed = true;
            Some(form.email.as_str())
        } else {
            None
        };

        let name = if user_in_db.name != form.name {
            changed = true;
            Some(form.name.as_str())
        } else {
            None
        };

        let role = if user_in_db.role as u8 != form.role {
            if let Ok(r) = Role::try_from(form.role) {
                changed = true;
                Some(r)
            } else {
                None
            }
        } else {
            None
        };

        let function = if user_in_db.function as u8 != form.function {
            if let Ok(f) = Function::try_from(form.function) {
                changed = true;
                Some(f)
            } else {
                None
            }
        } else {
            None
        };

        let area = if current_user.role == Role::Admin && form.area.is_some() && user_in_db.area_id != form.area.unwrap() {
            changed = true;
            Some(form.area.unwrap())
        } else {
            None
        };

        if changed {
            match User::update(pool.get_ref(), path.id, email, name, None, None, role, function, area, None, None).await {
                Ok(_) => return HttpResponse::Found().insert_header((LOCATION, "/users")).finish(),
                Err(err) => println!("{}", err)
            }
        }
    }

    return HttpResponse::BadRequest().body("Fehler beim Bearbeiten des Nutzers");
}
