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

namespace FabAccessAPI
{
    public class Connection
    {
        #region private variables
        private readonly TcpRpcClient? _rpcClient = null;
        private readonly IBootstrap? _bootstrapCap = null;
        private Auth? _auth = null;
        #endregion

        public TcpRpcClient? RpcClient => _rpcClient;

        #region Log
        //private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="rpcClient">Should be an already configured and connected TcpRpcClient</param>
        public Connection(TcpRpcClient rpcClient)
        {
            _rpcClient = rpcClient;
            _bootstrapCap = _rpcClient.GetMain<IBootstrap>();
            //_Log.Debug($"Done bootstraping API connection.");
        }

        /// <summary>
        /// Authenticate this connection.
        /// Calling this more then once is UB
        /// </summary>
        /// <param name="mech">The desired authentication mechanism</param>
        /// <param name="kvs">Key-Value data specific to the mechanism</param>
        /// <returns></returns>
        public async Task Auth(string mech, Dictionary<string, object> kvs, CancellationToken cancellationToken_ = default)
        {
            // _bootstrapCap = await _bootstrapCap.Unwrap();
            var authCap = await _bootstrapCap.AuthenticationSystem(cancellationToken_);
            _auth = new Auth(authCap);
            var mechs = await _auth.GetMechanisms();
            //_Log.Debug($"The Server supports the following auth mechs: {string.Join(", ", mechs)}");

            if (!mechs.Contains(mech))
            {
                throw new UnsupportedMechanismException();
            }

            await _auth.Authenticate(mech, kvs);
        }

        /// <summary>
        /// Get a wrapped capability to interact with machines
        /// </summary>
        /// <returns>A wrapped capability to interact with machines</returns>
        public async Task<IMachineSystem> AccessMachineSystem()
        {
            return await _bootstrapCap.MachineSystem();
        }

        /// <summary>
        /// Get a wrapped capability to interact with users
        /// </summary>
        /// <returns>A wrapped capability to interact with users</returns>
        public async Task<IUserSystem> AccessUserSystem()
        {
            return await _bootstrapCap.UserSystem();
        }

        /// <summary>
        /// Get a wrapped capability to interact with permissions
        /// </summary>
        /// <returns>A wrapped capability to interact with permissions</returns>
        public async Task<IPermissionSystem> AccessPermissionSystem()
        {
            return await _bootstrapCap.PermissionSystem();
        }
    }
}