use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use brass_macros::db_test;
use sqlx::PgPool;

use crate::{
    endpoints::location::LocationForm,
    models::{Location, Role, User},
    utils::ApplicationError,
};

#[cfg(test)]
use crate::utils::test_helper::{test_post, DbTestContext, RequestConfig, StatusCode};

#[actix_web::post("/locations/new")]
pub async fn post(
    user: web::ReqData<User>,
    pool: web::Data<PgPool>,
    form: web::Form<LocationForm>,
) -> 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();
    }

    Location::create(pool.get_ref(), &form.name, area_id).await?;

    return Ok(HttpResponse::Found()
        .insert_header((LOCATION, "/locations"))
        .insert_header(("HX-LOCATION", "/locations"))
        .finish());
}

#[db_test]
async fn works_when_user_is_admin(context: &DbTestContext) {
    let app = context.app().await;
    let config = RequestConfig {
        uri: "/locations/new".to_string(),
        role: Role::Admin,
        function: crate::models::Function::Posten,
        user_area: 1,
    };

    let form = LocationForm {
        name: "Hauptbahnhof".to_string(),
        area: Some(1),
    };

    let response = test_post(&context.db_pool, app, &config, form).await;
    assert_eq!(StatusCode::FOUND, response.status());

    assert_eq!(
        "Hauptbahnhof".to_string(),
        Location::read_by_id(&context.db_pool, 1)
            .await
            .unwrap()
            .unwrap()
            .name
    );
}

#[db_test]
async fn uses_area_id_of_area_manager(context: &DbTestContext) {
    let app = context.app().await;
    let config = RequestConfig {
        uri: "/locations/new".to_string(),
        role: Role::AreaManager,
        function: crate::models::Function::Posten,
        user_area: 1,
    };

    let form = LocationForm {
        name: "Hauptbahnhof".to_string(),
        area: None,
    };

    let response = test_post(&context.db_pool, app, &config, form).await;
    assert_eq!(StatusCode::FOUND, response.status());

    assert_eq!(
        "Hauptbahnhof".to_string(),
        Location::read_by_id(&context.db_pool, 1)
            .await
            .unwrap()
            .unwrap()
            .name
    );
}
