package svc_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"

	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
	permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
	storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
	"github.com/go-chi/chi/v5"
	"github.com/golang/protobuf/ptypes/empty"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	libregraph "github.com/owncloud/libre-graph-api-go"
	"github.com/owncloud/ocis/v2/ocis-pkg/shared"
	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
	settings "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
	"github.com/owncloud/ocis/v2/services/graph/mocks"
	"github.com/owncloud/ocis/v2/services/graph/pkg/config"
	"github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults"
	identitymocks "github.com/owncloud/ocis/v2/services/graph/pkg/identity/mocks"
	service "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0"
	settingsService "github.com/owncloud/ocis/v2/services/settings/pkg/service/v0"
	revactx "github.com/owncloud/reva/v2/pkg/ctx"
	"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
	cs3mocks "github.com/owncloud/reva/v2/tests/cs3mocks/mocks"
	"github.com/stretchr/testify/mock"
	merrors "go-micro.dev/v4/errors"
	"google.golang.org/grpc"
)

type assignmentList struct {
	Value []*libregraph.AppRoleAssignment
}

var _ = Describe("AppRoleAssignments", func() {
	var (
		svc             service.Service
		ctx             context.Context
		cfg             *config.Config
		gatewayClient   *cs3mocks.GatewayAPIClient
		gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
		eventsPublisher mocks.Publisher
		roleService     *mocks.RoleService
		identityBackend *identitymocks.Backend

		rr *httptest.ResponseRecorder

		currentUser = &userv1beta1.User{
			Id: &userv1beta1.UserId{
				OpaqueId: "user",
			},
		}
	)

	BeforeEach(func() {
		eventsPublisher.On("Publish", mock.Anything, mock.Anything, mock.Anything).Return(nil)

		identityBackend = &identitymocks.Backend{}
		roleService = &mocks.RoleService{}

		pool.RemoveSelector("GatewaySelector" + "com.owncloud.api.gateway")
		gatewayClient = &cs3mocks.GatewayAPIClient{}
		gatewaySelector = pool.GetSelector[gateway.GatewayAPIClient](
			"GatewaySelector",
			"com.owncloud.api.gateway",
			func(cc grpc.ClientConnInterface) gateway.GatewayAPIClient {
				return gatewayClient
			},
		)

		gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
			Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			User:   currentUser,
		}, nil)

		gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
			Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			StorageSpaces: []*storageprovider.StorageSpace{
				{Id: &storageprovider.StorageSpaceId{OpaqueId: "ps1"}},
			},
		}, nil)

		// Add CheckPermission mock for permission checks
		gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
			Status: &rpc.Status{Code: rpc.Code_CODE_OK},
		}, nil)

		rr = httptest.NewRecorder()
		ctx = context.Background()

		cfg = defaults.FullDefaultConfig()
		cfg.Identity.LDAP.CACert = "" // skip the startup checks, we don't use LDAP at all in this tests
		cfg.TokenManager.JWTSecret = "loremipsum"
		cfg.Commons = &shared.Commons{}
		cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
		cfg.Application.ID = "some-application-ID"

		svc, _ = service.NewService(
			service.Config(cfg),
			service.WithGatewaySelector(gatewaySelector),
			service.EventsPublisher(&eventsPublisher),
			service.WithIdentityBackend(identityBackend),
			service.WithRoleService(roleService),
		)
	})

	Describe("ListAppRoleAssignments", func() {
		It("lists the appRoleAssignments", func() {
			user := &libregraph.User{
				Id: libregraph.PtrString("user1"),
			}
			assignments := []*settingsmsg.UserRoleAssignment{
				{
					Id:          "some-appRoleAssignment-ID",
					AccountUuid: user.GetId(),
					RoleId:      "some-appRole-ID",
				},
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: assignments}, nil)

			r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/users/user1/appRoleAssignments", nil)
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", user.GetId())
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.ListAppRoleAssignments(rr, r)

			Expect(rr.Code).To(Equal(http.StatusOK))

			data, err := io.ReadAll(rr.Body)
			Expect(err).ToNot(HaveOccurred())

			responseList := assignmentList{}
			err = json.Unmarshal(data, &responseList)
			Expect(err).ToNot(HaveOccurred())
			Expect(len(responseList.Value)).To(Equal(1))
			Expect(responseList.Value[0].GetId()).ToNot(BeEmpty())
			Expect(responseList.Value[0].GetAppRoleId()).To(Equal("some-appRole-ID"))
			Expect(responseList.Value[0].GetPrincipalId()).To(Equal(user.GetId()))
			Expect(responseList.Value[0].GetResourceId()).To(Equal(cfg.Application.ID))

		})

	})

	Describe("CreateAppRoleAssignment", func() {
		It("creates an appRoleAssignment", func() {
			user := &libregraph.User{
				Id: libregraph.PtrString("user1"),
			}
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: user.GetId(),
				RoleId:      "some-appRole-ID",
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{
				Assignments: []*settingsmsg.UserRoleAssignment{
					userRoleAssignment,
				},
			}, nil)

			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId(user.GetId())
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", user.GetId())
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusCreated))

			data, err := io.ReadAll(rr.Body)
			Expect(err).ToNot(HaveOccurred())

			assignment := libregraph.AppRoleAssignment{}
			err = json.Unmarshal(data, &assignment)
			Expect(err).ToNot(HaveOccurred())
			Expect(assignment.GetId()).ToNot(BeEmpty())
			Expect(assignment.GetAppRoleId()).To(Equal("some-appRole-ID"))
			Expect(assignment.GetPrincipalId()).To(Equal("user1"))
			Expect(assignment.GetResourceId()).To(Equal(cfg.Application.ID))
		})

		It("returns bad request for invalid JSON", func() {
			invalidJson := `{"invalid": json}`
			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBufferString(invalidJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusBadRequest))
		})

		It("returns bad request when principal ID does not match user ID", func() {
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("different-user-id")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusBadRequest))
		})

		It("returns bad request when resource ID does not match application ID", func() {
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId("different-application-id")

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusBadRequest))
		})

		It("returns forbidden when AssignRoleToUser returns forbidden error", func() {
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(nil, merrors.Forbidden("test", "forbidden"))

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusForbidden))
		})

		It("returns internal server error when AssignRoleToUser returns general error", func() {
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("general error"))

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusInternalServerError))
		})

		It("disables personal space for UserLight role", func() {
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: "user1",
				RoleId:      settingsService.BundleUUIDRoleUserLight,
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			// Reset the mock and set up UserLight role scenario (permission denied for Drives.Create)
			gatewayClient.ExpectedCalls = nil
			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				User:   currentUser,
			}, nil)
			gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED},
			}, nil)
			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				StorageSpaces: []*storageprovider.StorageSpace{
					{Id: &storageprovider.StorageSpaceId{OpaqueId: "ps1"}},
				},
			}, nil)
			gatewayClient.On("DeleteStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.DeleteStorageSpaceResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId(settingsService.BundleUUIDRoleUserLight)
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusCreated))
		})

		It("ensures personal space for non-UserLight role", func() {
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: "user1",
				RoleId:      "some-appRole-ID",
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			// Reset the mock and set up non-UserLight role scenario (permission allowed for Drives.Create)
			gatewayClient.ExpectedCalls = nil
			gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)
			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				User:   currentUser,
			}, nil)
			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
				Status:        &rpc.Status{Code: rpc.Code_CODE_OK},
				StorageSpaces: []*storageprovider.StorageSpace{},
			}, nil)
			gatewayClient.On("CreateStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.CreateStorageSpaceResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusCreated))
		})

		It("handles old role assignment correctly", func() {
			oldRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "old-assignment-ID",
				AccountUuid: "user1",
				RoleId:      "old-role-ID",
			}
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: "user1",
				RoleId:      "some-appRole-ID",
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{
				Assignments: []*settingsmsg.UserRoleAssignment{oldRoleAssignment},
			}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			// Reset the mock and set up non-UserLight role scenario (permission allowed for Drives.Create)
			gatewayClient.ExpectedCalls = nil
			gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)
			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				User:   currentUser,
			}, nil)
			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
				Status:        &rpc.Status{Code: rpc.Code_CODE_OK},
				StorageSpaces: []*storageprovider.StorageSpace{},
			}, nil)
			gatewayClient.On("CreateStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.CreateStorageSpaceResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusCreated))
		})

		It("returns error when DisablePersonalSpace fails for UserLight role", func() {
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: "user1",
				RoleId:      settingsService.BundleUUIDRoleUserLight,
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			// Reset the mock and set up UserLight role scenario with failing DisablePersonalSpace
			gatewayClient.ExpectedCalls = nil
			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				User:   currentUser,
			}, nil)
			gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED},
			}, nil)
			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				StorageSpaces: []*storageprovider.StorageSpace{
					{Id: &storageprovider.StorageSpaceId{OpaqueId: "ps1"}},
				},
			}, nil)
			gatewayClient.On("DeleteStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.DeleteStorageSpaceResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL, Message: "internal error"},
			}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId(settingsService.BundleUUIDRoleUserLight)
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusInternalServerError))
		})

		It("returns error when GetUser fails for non-UserLight role", func() {
			userRoleAssignment := &settingsmsg.UserRoleAssignment{
				Id:          "some-appRoleAssignment-ID",
				AccountUuid: "user1",
				RoleId:      "some-appRole-ID",
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
			roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)

			// Reset the mock and make GetUser fail
			gatewayClient.ExpectedCalls = nil
			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("GetUser failed"))
			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
				StorageSpaces: []*storageprovider.StorageSpace{
					{Id: &storageprovider.StorageSpaceId{OpaqueId: "ps1"}},
				},
			}, nil)
			gatewayClient.On("DeleteStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.DeleteStorageSpaceResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)
			gatewayClient.On("CheckPermission", mock.Anything, mock.Anything).Return(&permissions.CheckPermissionResponse{
				Status: &rpc.Status{Code: rpc.Code_CODE_OK},
			}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId("user1")
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", "user1")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.CreateAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusCreated))
		})
	})

	Describe("DeleteAppRoleAssignment", func() {
		It("deletes an appRoleAssignment", func() {
			user := &libregraph.User{
				Id: libregraph.PtrString("user1"),
			}

			assignments := []*settingsmsg.UserRoleAssignment{
				{
					Id:          "some-appRoleAssignment-ID",
					AccountUuid: user.GetId(),
					RoleId:      "some-appRole-ID",
				},
			}
			roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: assignments}, nil)

			roleService.On("RemoveRoleFromUser", mock.Anything, mock.Anything, mock.Anything).Return(&empty.Empty{}, nil)

			ara := libregraph.NewAppRoleAssignmentWithDefaults()
			ara.SetAppRoleId("some-appRole-ID")
			ara.SetPrincipalId(user.GetId())
			ara.SetResourceId(cfg.Application.ID)

			araJson, err := json.Marshal(ara)
			Expect(err).ToNot(HaveOccurred())

			r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments/some-appRoleAssignment-ID", bytes.NewBuffer(araJson))
			rctx := chi.NewRouteContext()
			rctx.URLParams.Add("userID", user.GetId())
			rctx.URLParams.Add("appRoleAssignmentID", "some-appRoleAssignment-ID")
			r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
			svc.DeleteAppRoleAssignment(rr, r)

			Expect(rr.Code).To(Equal(http.StatusNoContent))

		})

	})
})
