package azure

import (
	"context"
	"errors"
	"net/http"
	"testing"

	azerrors "github.com/Azure/azure-sdk-for-go-extensions/pkg/errors"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
	azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3"
	rfake "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3/fake"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi/fake"
	. "github.com/onsi/gomega"
)

func TestNewIAMClient(t *testing.T) {
	g := NewWithT(t)
	_, err := NewIAMClient("fake", "fake", "fake", &azfake.TokenCredential{})
	g.Expect(err).To(Succeed())
}

func TestCreateUserIdentity(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *fake.UserAssignedIdentitiesServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armmsi.NewUserAssignedIdentitiesClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewUserAssignedIdentitiesServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				userIdentityCli: cli,
				resourceGroup:   "fake",
				location:        "eastus",
			}
			_, err = iam.CreateUserIdentity(context.TODO(), "fake")
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error case on User Identity creation", &fake.UserAssignedIdentitiesServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName string, parameters armmsi.Identity, options *armmsi.UserAssignedIdentitiesClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("successful path on User Identity creation", &fake.UserAssignedIdentitiesServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName string, parameters armmsi.Identity, options *armmsi.UserAssignedIdentitiesClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.UserAssignedIdentitiesClientCreateOrUpdateResponse{}, nil)
			return
		},
	}, nil)
}

func TestGetUserIdentity(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *fake.UserAssignedIdentitiesServer, expErr error, expExists bool) {
		t.Run(name, func(t *testing.T) {
			cli, err := armmsi.NewUserAssignedIdentitiesClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewUserAssignedIdentitiesServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				userIdentityCli: cli,
				resourceGroup:   "fake",
				location:        "eastus",
			}
			_, exists, err := iam.GetUserIdentity(context.TODO(), "fake")
			g.Expect(errors.Is(err, expErr)).To(BeTrue())
			g.Expect(exists == expExists).To(BeTrue())
		})
	}
	f("fake error when getting User Identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom, false)

	f("not found error when getting User Identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(&azcore.ResponseError{
				ErrorCode:  azerrors.ResourceNotFound,
				StatusCode: http.StatusNotFound,
			})
			return
		},
	}, nil, false)

	f("successful path get User Identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.UserAssignedIdentitiesClientGetResponse{}, nil)
			return
		},
	}, nil, true)
}

func TestGetWorkloadIdentity(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, uServer *fake.UserAssignedIdentitiesServer, fServer *fake.FederatedIdentityCredentialsServer, expErr error, expExist bool) {
		t.Run(name, func(t *testing.T) {
			uCli, err := armmsi.NewUserAssignedIdentitiesClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewUserAssignedIdentitiesServerTransport(uServer),
				},
			})
			g.Expect(err).To(Succeed())
			fCli, err := armmsi.NewFederatedIdentityCredentialsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewFederatedIdentityCredentialsServerTransport(fServer),
				},
			})
			g.Expect(err).To(Succeed())

			iam := &IAMClient{
				userIdentityCli: uCli,
				fedIdentityCli:  fCli,
				resourceGroup:   "fake",
				location:        "eastus",
			}
			_, exists, err := iam.GetWorkloadIdentity(context.TODO(), "fake")
			g.Expect(errors.Is(err, expErr)).To(BeTrue())
			g.Expect(exists == expExist).To(BeTrue())
		})
	}

	f("error getting user identity when getting workload identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, nil, errBoom, false)

	f("error listing federated identity when getting workload identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.UserAssignedIdentitiesClientGetResponse{}, nil)
			return
		},
	}, &fake.FederatedIdentityCredentialsServer{
		NewListPager: func(resourceGroupName, resourceName string, options *armmsi.FederatedIdentityCredentialsClientListOptions) (resp azfake.PagerResponder[armmsi.FederatedIdentityCredentialsClientListResponse]) {
			resp.AddError(errBoom)
			return
		},
	}, errBoom, true)

	f("successful when getting workload identity", &fake.UserAssignedIdentitiesServer{
		Get: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientGetOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientGetResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.UserAssignedIdentitiesClientGetResponse{}, nil)
			return
		},
	}, &fake.FederatedIdentityCredentialsServer{
		NewListPager: func(resourceGroupName, resourceName string, options *armmsi.FederatedIdentityCredentialsClientListOptions) (resp azfake.PagerResponder[armmsi.FederatedIdentityCredentialsClientListResponse]) {
			resp.AddPage(http.StatusOK, armmsi.FederatedIdentityCredentialsClientListResponse{
				FederatedIdentityCredentialsListResult: armmsi.FederatedIdentityCredentialsListResult{
					Value: []*armmsi.FederatedIdentityCredential{
						{
							Properties: &armmsi.FederatedIdentityCredentialProperties{},
						},
					},
				},
			}, nil)
			return
		},
	}, nil, true)
}

func TestCreateOrUpdateRoleAssignment(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			_, err = iam.CreateOrUpdateRoleAssignment(context.TODO(), "fake", "fake", nil)
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when creating role assignment", &rfake.RoleAssignmentsServer{
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("successful when creating role assignment", &rfake.RoleAssignmentsServer{
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armauthorization.RoleAssignmentsClientCreateResponse{}, nil)
			return
		},
	}, nil)
}

func TestCreateOrUpdateRoleAssignmentForPrincipal(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			_, err = iam.CreateOrUpdateRoleAssignmentForPrincipal(context.TODO(), "fake-scope", &armauthorization.RoleAssignmentProperties{
				PrincipalID: to.Ptr("fake"),
			})
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when listing existing role assignments", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddError(errBoom)
			return
		},
	}, errBoom)

	f("successful when updating existing role assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{
						{
							ID:   to.Ptr("fake"),
							Name: to.Ptr("fake"),
						},
					},
				},
			}, nil)
			return
		},
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armauthorization.RoleAssignmentsClientCreateResponse{}, nil)
			return
		},
	}, nil)

	f("successful when creating new role assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{},
				},
			}, nil)
			return
		},
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armauthorization.RoleAssignmentsClientCreateResponse{}, nil)
			return
		},
	}, nil)

	f("error when creating new role assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{},
				},
			}, nil)
			return
		},
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("role assignment exists conflict should fallback to existing assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func() func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			calls := 0
			return func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
				calls++
				if calls == 1 {
					resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
						RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{Value: []*armauthorization.RoleAssignment{}},
					}, nil)
					return
				}
				resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
					RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
						Value: []*armauthorization.RoleAssignment{{
							ID:   to.Ptr("fake-id"),
							Name: to.Ptr("existing-name"),
						}},
					},
				}, nil)
				return
			}
		}(),
		Create: func(ctx context.Context, scope, roleAssignmentName string, parameters armauthorization.RoleAssignmentCreateParameters, options *armauthorization.RoleAssignmentsClientCreateOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientCreateResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(&azcore.ResponseError{
				StatusCode: http.StatusConflict,
				ErrorCode:  ErrorCodeRoleAssignmentExists,
			})
			return
		},
	}, nil)
}

func TestCreateOrUpdateFederatedIdentity(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *fake.FederatedIdentityCredentialsServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armmsi.NewFederatedIdentityCredentialsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewFederatedIdentityCredentialsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				fedIdentityCli: cli,
				resourceGroup:  "fake",
				location:       "eastus",
			}
			err = iam.CreateOrUpdateFederatedIdentity(context.TODO(), "fake", "fake", []string{"fake"})
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when creating federated identity", &fake.FederatedIdentityCredentialsServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName, federatedIdentityCredentialResourceName string, parameters armmsi.FederatedIdentityCredential, options *armmsi.FederatedIdentityCredentialsClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("error list federated identity when update federated identity", &fake.FederatedIdentityCredentialsServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName, federatedIdentityCredentialResourceName string, parameters armmsi.FederatedIdentityCredential, options *armmsi.FederatedIdentityCredentialsClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse{}, nil)
			return
		},
		NewListPager: func(resourceGroupName, resourceName string, options *armmsi.FederatedIdentityCredentialsClientListOptions) (resp azfake.PagerResponder[armmsi.FederatedIdentityCredentialsClientListResponse]) {
			resp.AddError(errBoom)
			return
		},
	}, errBoom)

	f("error deleting federated identity when update federated identity", &fake.FederatedIdentityCredentialsServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName, federatedIdentityCredentialResourceName string, parameters armmsi.FederatedIdentityCredential, options *armmsi.FederatedIdentityCredentialsClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse{}, nil)
			return
		},
		NewListPager: func(resourceGroupName, resourceName string, options *armmsi.FederatedIdentityCredentialsClientListOptions) (resp azfake.PagerResponder[armmsi.FederatedIdentityCredentialsClientListResponse]) {
			resp.AddPage(http.StatusOK, armmsi.FederatedIdentityCredentialsClientListResponse{
				FederatedIdentityCredentialsListResult: armmsi.FederatedIdentityCredentialsListResult{
					Value: []*armmsi.FederatedIdentityCredential{
						{
							Name: to.Ptr("fake1"),
							Properties: &armmsi.FederatedIdentityCredentialProperties{
								Subject: to.Ptr("fake1"),
							},
						},
					},
				},
			}, nil)
			return
		},
		Delete: func(ctx context.Context, resourceGroupName, resourceName, federatedIdentityCredentialResourceName string, options *armmsi.FederatedIdentityCredentialsClientDeleteOptions) (resp azfake.Responder[armmsi.FederatedIdentityCredentialsClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("successful when creating federated identity", &fake.FederatedIdentityCredentialsServer{
		CreateOrUpdate: func(ctx context.Context, resourceGroupName, resourceName, federatedIdentityCredentialResourceName string, parameters armmsi.FederatedIdentityCredential, options *armmsi.FederatedIdentityCredentialsClientCreateOrUpdateOptions) (resp azfake.Responder[armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armmsi.FederatedIdentityCredentialsClientCreateOrUpdateResponse{}, nil)
			return
		},
		NewListPager: func(resourceGroupName, resourceName string, options *armmsi.FederatedIdentityCredentialsClientListOptions) (resp azfake.PagerResponder[armmsi.FederatedIdentityCredentialsClientListResponse]) {
			resp.AddPage(http.StatusOK, armmsi.FederatedIdentityCredentialsClientListResponse{}, nil)
			return
		},
	}, nil)
}

func TestNormalizeFederatedIdentityName(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"Some-String123", "Some-String123"},
		{"Invalid@String", "Invalid-String"},
		{"123:abc", "123-abc"},
		{"a@b#c", "a-b-c"},
		{"1", "1"},
		{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"},
		{"ThisIsAVeryLongStringThatShouldBeTruncatedAndMoreThisIsAVeryLongStringThatShouldBeTruncatedAndMoreThisIsAVeryLongStringThatShouldBeTruncatedAndMore", "ThisIsAVeryLongStringThatShouldBeTruncatedAndMoreThisIsAVeryLongStringThatShouldBeTruncatedAndMoreThisIsAVeryLongStringT"},
	}

	for _, test := range tests {
		result := normalizeFederatedIdentityName(test.input)
		if result != test.expected {
			t.Errorf("For input '%s', expected '%s' but got '%s'", test.input, test.expected, result)
		}
	}
}

func TestGetRoleAssignment(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expErr error, expExists bool) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			_, exist, err := iam.GetRoleAssignment(context.TODO(), "fake", "fake")
			g.Expect(errors.Is(err, expErr)).To(BeTrue())
			g.Expect(exist == expExists).To(BeTrue())
		})
	}

	f("error when getting role assignments", &rfake.RoleAssignmentsServer{
		Get: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientGetOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientGetResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom, false)

	f("not found when getting role assignments", &rfake.RoleAssignmentsServer{
		Get: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientGetOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientGetResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(&azcore.ResponseError{
				ErrorCode:  azerrors.ResourceNotFound,
				StatusCode: http.StatusNotFound,
			})
			return
		},
	}, nil, false)

	f("successful when getting role assignment", &rfake.RoleAssignmentsServer{
		Get: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientGetOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientGetResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armauthorization.RoleAssignmentsClientGetResponse{}, nil)
			return
		},
	}, nil, true)
}

func TestGetRoleAssignmentByPrincipalID(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expErr error, expExists bool) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			_, exist, err := iam.GetRoleAssignmentByPrincipalID(context.TODO(), "fake", "fake")
			g.Expect(errors.Is(err, expErr)).To(BeTrue())
			g.Expect(exist == expExists).To(BeTrue())
		})
	}

	f("error when listing role assignments", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddError(errBoom)
			return
		},
	}, errBoom, false)

	f("not found when listing role assignments", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{},
				},
			}, nil)
			return
		},
	}, nil, false)

	f("successful when listing role assignments", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{
						{
							ID: to.Ptr("fake"),
							Properties: &armauthorization.RoleAssignmentProperties{
								PrincipalID: to.Ptr("fake"),
							},
						},
					},
				},
			}, nil)
			return
		},
	}, nil, true)
}

func TestDeleteUserIdentity(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *fake.UserAssignedIdentitiesServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armmsi.NewUserAssignedIdentitiesClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: fake.NewUserAssignedIdentitiesServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				userIdentityCli: cli,
				resourceGroup:   "fake",
				location:        "eastus",
			}
			err = iam.DeleteUserIdentity(context.TODO(), "fake")
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when deleting user identity", &fake.UserAssignedIdentitiesServer{
		Delete: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientDeleteOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("not found when deleting user identity", &fake.UserAssignedIdentitiesServer{
		Delete: func(ctx context.Context, resourceGroupName, resourceName string, options *armmsi.UserAssignedIdentitiesClientDeleteOptions) (resp azfake.Responder[armmsi.UserAssignedIdentitiesClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(&azcore.ResponseError{
				ErrorCode:  azerrors.ResourceNotFound,
				StatusCode: http.StatusNotFound,
			})
			return
		},
	}, nil)
}

func TestDeleteRoleAssignment(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			err = iam.DeleteRoleAssignment(context.TODO(), "fake", "fake")
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when deleting role assignment", &rfake.RoleAssignmentsServer{
		Delete: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientDeleteOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("not found when deleting role assignment", &rfake.RoleAssignmentsServer{
		Delete: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientDeleteOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(&azcore.ResponseError{
				ErrorCode:  azerrors.ResourceNotFound,
				StatusCode: http.StatusNotFound,
			})
			return
		},
	}, nil)
}

func TestDeleteRoleAssignmentByPrincipalID(t *testing.T) {
	g := NewWithT(t)

	f := func(name string, server *rfake.RoleAssignmentsServer, expected error) {
		t.Run(name, func(t *testing.T) {
			cli, err := armauthorization.NewRoleAssignmentsClient("fake", &azfake.TokenCredential{}, &arm.ClientOptions{
				ClientOptions: azcore.ClientOptions{
					Transport: rfake.NewRoleAssignmentsServerTransport(server),
				},
			})
			g.Expect(err).To(Succeed())
			iam := &IAMClient{
				rbacCli:       cli,
				resourceGroup: "fake",
				location:      "eastus",
			}
			err = iam.DeleteRoleAssignmentByPrincipalID(context.TODO(), "fake", "fake")
			g.Expect(errors.Is(err, expected)).To(BeTrue())
		})
	}

	f("error when listing role assignments", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddError(errBoom)
			return
		},
	}, errBoom)

	f("error when deleting role assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{
						{
							ID:   to.Ptr("fake"),
							Name: to.Ptr("fake"),
							Properties: &armauthorization.RoleAssignmentProperties{
								PrincipalID: to.Ptr("fake"),
							},
						},
					},
				},
			}, nil)
			return
		},
		Delete: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientDeleteOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientDeleteResponse], errResp azfake.ErrorResponder) {
			errResp.SetError(errBoom)
			return
		},
	}, errBoom)

	f("success when deleting role assignment", &rfake.RoleAssignmentsServer{
		NewListForScopePager: func(scope string, options *armauthorization.RoleAssignmentsClientListForScopeOptions) (resp azfake.PagerResponder[armauthorization.RoleAssignmentsClientListForScopeResponse]) {
			resp.AddPage(http.StatusOK, armauthorization.RoleAssignmentsClientListForScopeResponse{
				RoleAssignmentListResult: armauthorization.RoleAssignmentListResult{
					Value: []*armauthorization.RoleAssignment{
						{
							ID:   to.Ptr("fake"),
							Name: to.Ptr("fake"),
							Properties: &armauthorization.RoleAssignmentProperties{
								PrincipalID: to.Ptr("fake"),
							},
						},
					},
				},
			}, nil)
			return
		},
		Delete: func(ctx context.Context, scope, roleAssignmentName string, options *armauthorization.RoleAssignmentsClientDeleteOptions) (resp azfake.Responder[armauthorization.RoleAssignmentsClientDeleteResponse], errResp azfake.ErrorResponder) {
			resp.SetResponse(http.StatusOK, armauthorization.RoleAssignmentsClientDeleteResponse{}, nil)
			return
		},
	}, nil)
}
