using System.Reflection;
using H.Pipes.Args;
using InABox.API;
using InABox.Clients;
using InABox.Core;
using InABox.IPC;

namespace InABox.Rpc
{

    public class RpcServer<TTransport> : IDisposable, IRpcServer where TTransport : IRpcServerTransport
    {
        private TTransport _transport;

        public event LogEvent? OnLog;
        
        public bool IsSecure() => _transport?.IsSecure() ?? false;

        public RpcServer(TTransport transport)
        {
            _transport = transport;

            _transport.OnOpen += Transport_OnOpen;
            _transport.OnClose += Transport_OnClose;
            _transport.OnException += Transport_OnException;

            _transport.BeforeMessage += Transport_BeforeMessage;
            _transport.AfterMessage += Transport_AfterMessage;

            _transport.AddHandler(new RpcPingHandler(this));
            _transport.AddHandler(new RpcInfoHandler(this));

            _transport.AddHandler(new RpcValidateHandler(this));
            _transport.AddHandler(new RpcCheck2FAHandler(this));

            _transport.AddHandler(new RpcQueryHandler(this));
            _transport.AddHandler(new RpcSaveHandler(this));
            _transport.AddHandler(new RpcDeleteHandler(this));

            _transport.AddHandler(new RpcVersionHandler(this));
            _transport.AddHandler(new RpcInstallerHandler(this));
            _transport.AddHandler(new RpcReleaseNotesHandler(this));
        }

        private void Transport_OnOpen(IRpcTransport transport, RpcTransportOpenArgs e)
        {
            if ((e.Session?.ID ?? Guid.Empty) != Guid.Empty)
                OnLog?.Invoke(LogType.Information, "", $"Client Connected [{e.Session?.ID}]", Guid.Empty);
        }

        private void Transport_OnClose(IRpcTransport transport, RpcTransportCloseArgs e)
        {
            if ((e.Session?.ID ?? Guid.Empty) != Guid.Empty)
                OnLog?.Invoke(LogType.Information, "", $"Client Disconnected({e.Type}) [{e.Session?.ID}]", Guid.Empty);
        }

        private void Transport_BeforeMessage(IRpcTransport transport, RpcTransportMessageArgs e)
        {
            //OnLog?.Invoke(LogType.Information, "", $"Request Received [{e.Session?.ID}]: {e.Message?.Command ?? "Unknown"}");
        }

        private void Transport_AfterMessage(IRpcTransport transport, RpcTransportMessageArgs e)
        {
            //OnLog?.Invoke(LogType.Information, "", $"Sending Response [{e.Session?.ID}]: {e.Message?.Command ?? "Unknown"}");
        }

        private void Transport_OnException(IRpcTransport transport, RpcTransportExceptionArgs e)
        {
            if ((e.Session?.ID ?? Guid.Empty) != Guid.Empty)
                OnLog?.Invoke(LogType.Error, $"", $"Exception Occurred in {e.Session?.ID}: {e.Exception.Message}", Guid.Empty);
        }

        public void Start()
        {
            _transport.Start();
        }

        public void Stop()
        {
            _transport.Stop();
        }
        
        public void Dispose()
        {
            _transport?.Stop();
        }

        ~RpcServer()
        {
            Dispose();
        }
    }
}

