use axum::http::StatusCode;
use helpers::*;
use serde_json::json;

mod helpers;

#[tokio::test]
#[ignore = "integration test — requires database"]
async fn test_identity_crud_and_permission_assignment_flow() {
    let ctx = TestContext::new()
        .await
        .expect("Failed to create test context")
        .with_admin_auth()
        .await
        .expect("Failed to create admin-authenticated test user");

    let create_identity_response = ctx
        .post(
            "/api/v1/identities",
            json!({
                "login": "managed_user",
                "display_name": "Managed User",
                "password": "ManagedPass123!",
                "attributes": {
                    "department": "platform"
                }
            }),
            ctx.token(),
        )
        .await
        .expect("Failed to create identity");

    assert_eq!(create_identity_response.status(), StatusCode::CREATED);

    let created_identity: serde_json::Value = create_identity_response
        .json()
        .await
        .expect("Failed to parse identity create response");
    let identity_id = created_identity["data"]["id"]
        .as_i64()
        .expect("Missing identity id");

    let list_identities_response = ctx
        .get("/api/v1/identities", ctx.token())
        .await
        .expect("Failed to list identities");
    assert_eq!(list_identities_response.status(), StatusCode::OK);

    let identities_body: serde_json::Value = list_identities_response
        .json()
        .await
        .expect("Failed to parse identities response");
    assert!(identities_body["data"]
        .as_array()
        .expect("Expected data array")
        .iter()
        .any(|item| item["login"] == "managed_user"));

    let update_identity_response = ctx
        .put(
            &format!("/api/v1/identities/{}", identity_id),
            json!({
                "display_name": "Managed User Updated",
                "attributes": {
                    "department": "security"
                }
            }),
            ctx.token(),
        )
        .await
        .expect("Failed to update identity");
    assert_eq!(update_identity_response.status(), StatusCode::OK);

    let get_identity_response = ctx
        .get(&format!("/api/v1/identities/{}", identity_id), ctx.token())
        .await
        .expect("Failed to get identity");
    assert_eq!(get_identity_response.status(), StatusCode::OK);

    let identity_body: serde_json::Value = get_identity_response
        .json()
        .await
        .expect("Failed to parse get identity response");
    assert_eq!(
        identity_body["data"]["display_name"],
        "Managed User Updated"
    );
    assert_eq!(
        identity_body["data"]["attributes"]["department"],
        "security"
    );

    let permission_sets_response = ctx
        .get("/api/v1/permissions/sets", ctx.token())
        .await
        .expect("Failed to list permission sets");
    assert_eq!(permission_sets_response.status(), StatusCode::OK);

    let assignment_response = ctx
        .post(
            "/api/v1/permissions/assignments",
            json!({
                "identity_id": identity_id,
                "permission_set_ref": "core.admin"
            }),
            ctx.token(),
        )
        .await
        .expect("Failed to create permission assignment");
    assert_eq!(assignment_response.status(), StatusCode::CREATED);

    let assignment_body: serde_json::Value = assignment_response
        .json()
        .await
        .expect("Failed to parse permission assignment response");
    let assignment_id = assignment_body["data"]["id"]
        .as_i64()
        .expect("Missing assignment id");
    assert_eq!(assignment_body["data"]["permission_set_ref"], "core.admin");

    let list_assignments_response = ctx
        .get(
            &format!("/api/v1/identities/{}/permissions", identity_id),
            ctx.token(),
        )
        .await
        .expect("Failed to list identity permissions");
    assert_eq!(list_assignments_response.status(), StatusCode::OK);

    let assignments_body: serde_json::Value = list_assignments_response
        .json()
        .await
        .expect("Failed to parse identity permissions response");
    assert!(assignments_body
        .as_array()
        .expect("Expected array response")
        .iter()
        .any(|item| item["permission_set_ref"] == "core.admin"));

    let delete_assignment_response = ctx
        .delete(
            &format!("/api/v1/permissions/assignments/{}", assignment_id),
            ctx.token(),
        )
        .await
        .expect("Failed to delete assignment");
    assert_eq!(delete_assignment_response.status(), StatusCode::OK);

    let delete_identity_response = ctx
        .delete(&format!("/api/v1/identities/{}", identity_id), ctx.token())
        .await
        .expect("Failed to delete identity");
    assert_eq!(delete_identity_response.status(), StatusCode::OK);

    let missing_identity_response = ctx
        .get(&format!("/api/v1/identities/{}", identity_id), ctx.token())
        .await
        .expect("Failed to fetch deleted identity");
    assert_eq!(missing_identity_response.status(), StatusCode::NOT_FOUND);
}

#[tokio::test]
#[ignore = "integration test — requires database"]
async fn test_plain_authenticated_user_cannot_manage_identities() {
    let ctx = TestContext::new()
        .await
        .expect("Failed to create test context")
        .with_auth()
        .await
        .expect("Failed to authenticate plain test user");

    let response = ctx
        .get("/api/v1/identities", ctx.token())
        .await
        .expect("Failed to call identities endpoint");

    assert_eq!(response.status(), StatusCode::FORBIDDEN);
}
