using Capnp.Rpc;
using FabAccessAPI;
using FabAccessAPI.Schema;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace FabAccessAPI_Test.API_TestEnv
{
    [TestFixture]
    public class UserSystem_Test
    {
        #region SetUp
        [SetUp]
        public async Task SetUp()
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData("Admin1");
            await api.Connect(connectionData);

            IReadOnlyList<User> user_list = await api.Session.UserSystem.Manage.GetUserList().ConfigureAwait(false);

            List<Task> tasks = new List<Task>();
            foreach (User u in user_list)
            {
                if(u.Username.StartsWith("New"))
                {
                    tasks.Add(api.Session.UserSystem.Manage.RemoveUser(u));
                }
            }

            await Task.WhenAll(tasks);
        }
        #endregion

        [TestCase("Admin1", "NewUserA1")]
        [Order(1)]
        public async Task AddUser_DEPRECATED(string username, string username2)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            bool methodNotImplemented = false;

            try
            {
                User user = (await api.Session.UserSystem.Manage.AddUser(username2, TestEnv.PASSWORD).ConfigureAwait(false));
            }
            catch (RpcException exception) when (string.Equals(exception.Message, "method not implemented", StringComparison.Ordinal))
            {
                methodNotImplemented = true;
            }

            await api.Disconnect();

            Assert.IsTrue(methodNotImplemented);
        }

        [TestCase("Admin1", "NewUserA1")]
        [TestCase("Admin1", "NewUserB1")]
        [TestCase("Admin1", "NewUserC1")]
        [Order(1)]
        public async Task AddUser(string username, string username2)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            User user = (await api.Session.UserSystem.Manage.AddUserFallible(username2, TestEnv.PASSWORD).ConfigureAwait(false)).Successful;

            await api.Disconnect();

            Assert.IsNotNull(user);
        }

        [TestCase("Admin1", "Admin1")]
        [TestCase("Admin1", "ManagerA1")]
        [TestCase("Admin1", "MakerA1")]
        [TestCase("Admin1", "GuestA1")]
        [Order(2)]
        public async Task AddUser_AllreadyExists(string username, string username2)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            UserSystem.ManageInterface.AddUserError.AddUserErrorEnum error = (await api.Session.UserSystem.Manage.AddUserFallible(username2, TestEnv.PASSWORD).ConfigureAwait(false)).Failed.Error;
            await api.Disconnect();

            Assert.AreEqual(UserSystem.ManageInterface.AddUserError.AddUserErrorEnum.alreadyExists, error);
        }

        [TestCase("Admin1", "")]
        [Order(2)]
        public async Task AddUser_InvalidUsername(string username, string username2)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            UserSystem.ManageInterface.AddUserError.AddUserErrorEnum error = (await api.Session.UserSystem.Manage.AddUserFallible(username2, TestEnv.PASSWORD).ConfigureAwait(false)).Failed.Error;
            await api.Disconnect();

            Assert.AreEqual(UserSystem.ManageInterface.AddUserError.AddUserErrorEnum.usernameInvalid, error);
        }

        [TestCase("Admin1", "NewUserC1", "")]
        [Order(2)]
        public async Task AddUser_InvalidPassword(string username, string username2, string password)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            UserSystem.ManageInterface.AddUserError.AddUserErrorEnum error = (await api.Session.UserSystem.Manage.AddUserFallible(username2, password).ConfigureAwait(false)).Failed.Error;
            await api.Disconnect();

            Assert.AreEqual(UserSystem.ManageInterface.AddUserError.AddUserErrorEnum.passwordInvalid, error);
        }

        [TestCase("Admin1", "NewUserA1")]
        [TestCase("Admin1", "NewUserB1")]
        [TestCase("Admin1", "NewUserC1")]
        [Order(3)]
        public async Task AddRemoveUser(string username, string username2)
        {
            API api = new API();
            ConnectionData connectionData = TestEnv.CreateConnetionData(username);
            await api.Connect(connectionData);

            User user = (await api.Session.UserSystem.Manage.AddUserFallible(username2, TestEnv.PASSWORD).ConfigureAwait(false)).Successful;

            await api.Session.UserSystem.Manage.RemoveUser(user);

            await api.Disconnect();

            Assert.IsNotNull(user);
        }
    }
}