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

namespace FabAccessAPI_Test
{
    public class API_Test
    {
        [Test]
        public async Task Connect_HostUnreachable()
        {
            API api = new API();

            ConnectionData connectionData = new ConnectionData()
            {
                Host = new UriBuilder(TestEnv.SCHEMA, "UnkownHost" + TestEnv.TESTSERVER, TestEnv.TESTSERVER_PORT).Uri,
                Mechanism = Mechanism.PLAIN,
                Username = "UnkownUser",
                Properties = new Dictionary<string, object>()
                {
                    { "Username", "UnkownUser" },
                    { "Password", TestEnv.PASSWORD }
                }
            };

            try
            {
                await api.Connect(connectionData);
            }
            catch (ConnectingFailedException)
            {
                Assert.Pass();
            }
            Assert.Fail();
        }

        [Test, Ignore("")]
        public async Task Connect_InvalidCredentials()
        {
            API api = new API();

            ConnectionData connectionData = TestEnv.CreateConnetionData("UnkownUser");

            try
            {
                await api.Connect(connectionData);
            }
            catch(InvalidCredentialsException)
            {
                Assert.Pass();
            }
            Assert.Fail();
        }

        [TestCase("Admin1")]
        public async Task ConnectDisconnect(string username)
        {
            API api = new API();

            ConnectionData connectionData = TestEnv.CreateConnetionData(username);

            bool event_Connected = false;
            bool event_Disconnected = false;
            api.ConnectionStatusChanged += (sender, eventArgs) =>
            {
                if (eventArgs == ConnectionStatusChange.Connected)
                {
                    event_Connected = true;
                }
                if(eventArgs == ConnectionStatusChange.Disconnected)
                {
                    event_Disconnected = true;
                }
            };

            await api.Connect(connectionData);

            bool HasSesion = api.Session != null;
            bool HasConnectionData = api.ConnectionData != null;
            bool HasConnectionInfo = api.ConnectionInfo != null;
            bool IsConnected = api.IsConnected;

            await api.Disconnect();

            Thread.Sleep(3000);
            Assert.Multiple(() =>
            {
                Assert.IsTrue(event_Connected, "event_Connected");
                Assert.IsTrue(event_Disconnected, "event_Disconnected");

                Assert.IsTrue(HasSesion, "HasSesion");
                Assert.IsTrue(HasConnectionData, "HasConnectionData");
                Assert.IsTrue(HasConnectionInfo, "HasConnectionInfo");
                Assert.IsTrue(IsConnected, "IsConnected");

                Assert.IsFalse(api.IsConnected, "api.IsConnected");
            });
        }

        [TestCase("Admin1")]
        public async Task TestConnectíon(string username)
        {
            API api = new API();

            ConnectionData connectionData = TestEnv.CreateConnetionData(username);

            ConnectionInfo connectionInfo = await api.TestConnection(connectionData);

            Assert.IsNotNull(connectionInfo);
        }

        [TestCase("Admin1"), Explicit]
        public async Task Reconnect(string username)
        {
            API api = new API();

            ConnectionData connectionData = TestEnv.CreateConnetionData(username);

            bool event_Connected = false;
            bool event_ConnectionLoss = false;
            bool event_Reconnect = false;
            bool event_Disconnected = false;

            api.ConnectionStatusChanged += (sender, eventArgs) =>
            {
                if (eventArgs == ConnectionStatusChange.Connected)
                {
                    event_Connected = true;
                }
                if (eventArgs == ConnectionStatusChange.ConnectionLoss)
                {
                    event_ConnectionLoss = true;
                }
                if (eventArgs == ConnectionStatusChange.Reconnected)
                {
                    event_Reconnect = true;
                }
                if (eventArgs == ConnectionStatusChange.Disconnected)
                {
                    event_Disconnected = true;
                }
            };

            TcpRpcClient tcpRpcClient = new TcpRpcClient();
            await api.Connect(connectionData, tcpRpcClient);

            try
            {
                // Stop here and cut internet connection
                await api.Session.MachineSystem.Info.GetMachineList().ConfigureAwait(false);
            }
            catch
            {

            }
            Thread.Sleep(3000);

            // Stop here and connect with internet again
            await api.Reconnect();
            await api.Disconnect();

            Thread.Sleep(3000);
            Assert.Multiple(() =>
            {
                Assert.IsTrue(event_Connected, "event_Connected");
                Assert.IsTrue(event_ConnectionLoss, "event_ConnectionLoss");
                Assert.IsTrue(event_Reconnect, "event_Reconnect");
                Assert.IsTrue(event_Disconnected, "event_Disconnected");
            });
        }


    }
}
