LoadDataAsync(Guid projectId, Guid projectTenantId)
        {
            var guestContextTask = _projectGuestContextService.GetProjectGuestContextAsync();
            var projectUsersTask = _serviceToServiceProjectAccessApi.GetProjectMemberUserIdsAsync(projectId, MemberRoleFilter.FullUser, new List <KeyValuePair <string, string> >()
            {
                HeaderKeys.CreateTenantHeaderKey(projectTenantId)
            });

            await Task.WhenAll(guestContextTask, projectUsersTask);

            var guestContext         = await guestContextTask;
            var projectUsersResponse = await projectUsersTask;

            return(guestContext, projectUsersResponse);
        }
        public async Task <CurrentProjectState> SetProjectGuestContextAsync(Guid projectId, string accessCode, Guid currentUserId, Guid?currentUserTenantId, Guid principalId)
        {
            if (projectId.Equals(Guid.Empty))
            {
                return(await ClearGuestSessionState(currentUserId));
            }

            var projectResponse = await _serviceToServiceProjectApi.GetProjectByIdAsync(projectId);

            if (!projectResponse.IsSuccess() || projectResponse.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching project {projectId} with service to service client, {projectResponse?.ResponseCode} - {projectResponse?.ReasonPhrase}");
            }

            var projectTenantId = projectResponse.Payload.TenantId;

            (ProjectGuestContext guestContext,
             MicroserviceResponse <IEnumerable <Guid> > projectUsersResponse) = await LoadDataAsync(projectId, projectTenantId);


            if (!projectUsersResponse.IsSuccess() || projectUsersResponse.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching project users {projectId}, {projectUsersResponse.ResponseCode} - {projectUsersResponse.ReasonPhrase}");
            }

            var project = projectResponse?.Payload;
            var userIsFullProjectMember = projectUsersResponse.Payload.Any(userId => userId == currentUserId);

            if (UserHasActiveProjectGuestContext(guestContext) && userIsFullProjectMember)
            {
                //User is in project's account and was a guest who was promoted to a full
                //member, clear guest properties. This changes the return value of ProjectGuestContextService.IsGuestAsync() to false.
                guestContext = new ProjectGuestContext();
                await _projectGuestContextService.SetProjectGuestContextAsync(guestContext);
            }

            var userHasAccess = UserHasActiveProjectGuestContext(guestContext) ?
                                await IsGuestCurrentlyAdmittedToProjectAsync(guestContext.GuestSessionId) :
                                userIsFullProjectMember;

            if (userHasAccess)
            {
                return(await CreateCurrentProjectState(project, true));
            }

            if (UserHasActiveProjectGuestContext(guestContext) && guestContext?.ProjectId == project?.Id)
            {
                return(await CreateCurrentProjectState(project, false));
            }

            var userResponse = await _userApi.GetUserAsync(currentUserId);

            if (!userResponse.IsSuccess() || userResponse?.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching user for {currentUserId}, {userResponse?.ResponseCode} - {userResponse?.ReasonPhrase}");
            }

            var userName      = !string.IsNullOrEmpty(userResponse.Payload.Email) ? userResponse.Payload.Email : userResponse.Payload.Username;
            var verifyRequest = new GuestVerificationRequest {
                Username = userName, ProjectAccessCode = accessCode, ProjectId = projectId
            };

            var guestVerifyResponse = await _guestSessionController.VerifyGuestAsync(verifyRequest, project, currentUserTenantId);

            if (guestVerifyResponse.ResultCode != VerifyGuestResponseCode.Success)
            {
                throw new InvalidOperationException($"Failed to verify guest for User.Id = {currentUserId}, Project.Id = {projectId}. ResponseCode = {guestVerifyResponse.ResultCode}. Reason = {guestVerifyResponse.Message}");
            }

            var newSession = await _guestSessionController.CreateGuestSessionAsync(new GuestSession
            {
                UserId            = currentUserId,
                ProjectId         = projectId,
                ProjectAccessCode = project.GuestAccessCode,
                GuestSessionState = InternalApi.Enums.GuestState.InLobby
            }, principalId, projectTenantId);

            await _projectGuestContextService.SetProjectGuestContextAsync(new ProjectGuestContext()
            {
                GuestSessionId = newSession.Id,
                ProjectId      = project.Id,
                GuestState     = Guest.ProjectContext.Enums.GuestState.InLobby,
                TenantId       = project.TenantId
            });


            if (!userIsFullProjectMember)
            {
                var request = new GrantProjectMembershipRequest
                {
                    UserId    = currentUserId,
                    ProjectId = project.Id,
                    Role      = MemberRole.GuestUser
                };
                var grantUserResponse = await _serviceToServiceProjectAccessApi.GrantProjectMembershipAsync(request, new List <KeyValuePair <string, string> > {
                    HeaderKeys.CreateTenantHeaderKey(projectTenantId)
                });

                if (!grantUserResponse.IsSuccess())
                {
                    throw new InvalidOperationException("Failed to add user to project");
                }
            }

            return(await CreateCurrentProjectState(project, false));
        }