context: using Microsoft.VisualStudio.TestTools.UnitTesting;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading;
  using System.Threading.Tasks;
  
  using Tgstation.Server.Api.Models;
  using Tgstation.Server.Api.Models.Request;
  using Tgstation.Server.Api.Models.Response;
  using Tgstation.Server.Api.Rights;
  using Tgstation.Server.Client;
  using Tgstation.Server.Host.System;
  
  namespace Tgstation.Server.Tests
  {
  	sealed class UsersTest
  	{
  		readonly IServerClient serverClient;
  
  		public UsersTest(IServerClient serverClient)
  		{
  			this.serverClient = serverClient ?? throw new ArgumentNullException(nameof(serverClient));
  		}
  
  		public async Task Run(CancellationToken cancellationToken)
  		{
  			await Task.WhenAll(
  				BasicTests(cancellationToken),
  				TestCreateSysUser(cancellationToken),
  				TestSpamCreation(cancellationToken)).ConfigureAwait(false);
  
  			await TestPagination(cancellationToken);
  		}
  
  		async Task BasicTests(CancellationToken cancellationToken)
  		{
  			var user = await serverClient.Users.Read(cancellationToken).ConfigureAwait(false);
  			Assert.IsNotNull(user);
  			Assert.AreEqual("Admin", user.Name);
  			Assert.IsNull(user.SystemIdentifier);
  			Assert.AreEqual(true, user.Enabled);
  			Assert.IsNotNull(user.OAuthConnections);
  			Assert.IsNotNull(user.PermissionSet);
  			Assert.IsNotNull(user.PermissionSet.Id);
  			Assert.IsNotNull(user.PermissionSet.InstanceManagerRights);
  			Assert.IsNotNull(user.PermissionSet.AdministrationRights);
  
  			var systemUser = user.CreatedBy;
  			Assert.IsNotNull(systemUser);
  			Assert.AreEqual("TGS", systemUser.Name);
  
  			var users = await serverClient.Users.List(null, cancellationToken);
  			Assert.IsTrue(users.Count > 0);
  			Assert.IsFalse(users.Any(x => x.Id == systemUser.Id));
  
  			await ApiAssert.ThrowsException<InsufficientPermissionsException>(() => serverClient.Users.GetId(systemUser, cancellationToken), null);
  			await ApiAssert.ThrowsException<InsufficientPermissionsException>(() => serverClient.Users.Update(new UserUpdateRequest
  			{
  				Id = systemUser.Id
  			}, cancellationToken), null);
  
  			var sampleOAuthConnections = new List<OAuthConnection>
  			{
  				new OAuthConnection
  				{
  					ExternalUserId = "asdfasdf",
  					Provider = OAuthProvider.Discord
  				}
  			};
  			await ApiAssert.ThrowsException<ApiConflictException>(() => serverClient.Users.Update(new UserUpdateRequest
  			{
  				Id = user.Id,
  				OAuthConnections = sampleOAuthConnections
  			}, cancellationToken), ErrorCode.AdminUserCannotOAuth);
  
  			var testUser = await serverClient.Users.Create(
  				new UserCreateRequest
  				{
  					Name = $"BasicTestUser",
  					Password = "asdfasdjfhauwiehruiy273894234jhndjkwh"
  				},
  				cancellationToken).ConfigureAwait(false);
  
  			Assert.IsNotNull(testUser.OAuthConnections);
  			testUser = await serverClient.Users.Update(
  			   new UserUpdateRequest
  			   {
  				   Id = testUser.Id,
  				   OAuthConnections = sampleOAuthConnections
  			   },
  			   cancellationToken).ConfigureAwait(false);
  
  			Assert.AreEqual(1, testUser.OAuthConnections.Count);
  			Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections.First().ExternalUserId);
  			Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections.First().Provider);
  
  
  			var group = await serverClient.Groups.Create(
  				new UserGroupCreateRequest
  				{
  					Name = "TestGroup"
  				},
  				cancellationToken);
  			Assert.AreEqual(group.Name, "TestGroup");
  			Assert.IsNotNull(group.PermissionSet);
  			Assert.IsNotNull(group.PermissionSet.Id);
  			Assert.AreEqual(AdministrationRights.None, group.PermissionSet.AdministrationRights);
  			Assert.AreEqual(InstanceManagerRights.None, group.PermissionSet.InstanceManagerRights);
  
  			var group2 = await serverClient.Groups.Create(new UserGroupCreateRequest
  			{
  				Name = "TestGroup2",
  				PermissionSet = new PermissionSet
  				{
  					InstanceManagerRights = InstanceManagerRights.List
  				}
  			}, cancellationToken);
  			Assert.AreEqual(AdministrationRights.None, group2.PermissionSet.AdministrationRights);
  			Assert.AreEqual(InstanceManagerRights.List, group2.PermissionSet.InstanceManagerRights);
  
  			var groups = await serverClient.Groups.List(null, cancellationToken);
  			Assert.AreEqual(2, groups.Count);
  
  			foreach (var igroup in groups)
  			{
  				Assert.IsNotNull(igroup.Users);
  				Assert.IsNotNull(igroup.PermissionSet);
  			}
  
  			await serverClient.Groups.Delete(group2, cancellationToken);
  
  			groups = await serverClient.Groups.List(null, cancellationToken);
  			Assert.AreEqual(1, groups.Count);
  
  			group = await serverClient.Groups.Update(new UserGroupUpdateRequest
  			{
  				Id = groups.First().Id,
  				PermissionSet = new PermissionSet
  				{
  					InstanceManagerRights = RightsHelper.AllRights<InstanceManagerRights>(),
  					AdministrationRights = RightsHelper.AllRights<AdministrationRights>(),
  				}
  			}, cancellationToken);
  
  			Assert.AreEqual(RightsHelper.AllRights<AdministrationRights>(), group.PermissionSet.AdministrationRights);
  			Assert.AreEqual(RightsHelper.AllRights<InstanceManagerRights>(), group.PermissionSet.InstanceManagerRights);
  
  			UserUpdateRequest testUserUpdate = new UserCreateRequest
  			{
  				Name = "TestUserWithNoPassword",
  				Password = String.Empty
  			};
  
  			await ApiAssert.ThrowsException<ApiConflictException>(() => serverClient.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken), ErrorCode.UserPasswordLength);
  
  			testUserUpdate.OAuthConnections = new List<OAuthConnection>
  			{
  				new OAuthConnection
  				{
  					ExternalUserId = "asdf",
  					Provider = OAuthProvider.GitHub
  				}
  			};
  
  			var testUser2 = await serverClient.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken);
  
  			testUserUpdate = new UserUpdateRequest
  			{
  				Id = testUser2.Id,
  				PermissionSet = testUser2.PermissionSet,
  				Group = new Api.Models.Internal.UserGroup
  				{
  					Id = group.Id
  				},
  			};
  			await ApiAssert.ThrowsException<ApiConflictException>(
  				() => serverClient.Users.Update(
  					testUserUpdate,
  					cancellationToken),
  				ErrorCode.UserGroupAndPermissionSet);
  
  			testUserUpdate.PermissionSet = null;
  
  			testUser2 = await serverClient.Users.Update(testUserUpdate, cancellationToken);
  
  			Assert.IsNull(testUser2.PermissionSet);
  			Assert.IsNotNull(testUser2.Group);
  			Assert.AreEqual(group.Id, testUser2.Group.Id);
  
  			group = await serverClient.Groups.GetId(group, cancellationToken);
  			Assert.IsNotNull(group.Users);
  			Assert.AreEqual(1, group.Users.Count);
  			Assert.AreEqual(testUser2.Id, group.Users.First().Id);
  			Assert.IsNotNull(group.PermissionSet);
  		}
  
  		async Task TestCreateSysUser(CancellationToken cancellationToken)
  		{
  			var sysId = Environment.UserName;
  			var update = new UserCreateRequest
  			{
  				SystemIdentifier = sysId
  			};
  			if (new PlatformIdentifier().IsWindows)
  
gt: 				await serverClient.Users.Create(update, cancellationToken);