
using InABox.Core;
using WebSocketSharp;
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;

namespace InABox.IPC
{
    public class RPCClientSocketTransport : RPCClientTransport
    {
        private WebSocket _socket;
        
        public RPCClientSocketTransport(string url)
        {
            _socket = new WebSocket($"ws://{url}");
            _socket.OnOpen += Socket_OnOpen;
            _socket.OnError += Socket_OnError;
            _socket.OnClose += Socket_OnClose;
            _socket.OnMessage += Socket_OnMessage;
            
            // Time to wait before disconnect - the default meant that the client disconnected during debugging, since the ping would fail
            _socket.WaitTime = TimeSpan.FromMinutes(10); 
        }
        
        private void Socket_OnOpen(object? sender, EventArgs e)
        {
            DoOpen();
        }
        
        private void Socket_OnMessage(object? sender, MessageEventArgs e)
        {
            RPCMessage? message = null;
            if ((e.IsBinary) && (e.RawData != null))
                message = Serialization.ReadBinary<RPCMessage>(e.RawData, BinarySerializationSettings.Latest);
            else if ((e.IsText) && !String.IsNullOrWhiteSpace(e.Data))
                message = Serialization.Deserialize<RPCMessage>(e.Data);
     
            Accept(message);
        }

        private void Socket_OnClose(object? sender, CloseEventArgs e)
        {
            DoClose(RPCTransportCloseEventType.Closed);
        }

        private void Socket_OnError(object? sender, ErrorEventArgs e)
        {
            DoException(e.Exception);
        }


        public override void Connect()
        {
            _socket.Connect();
        }
        
        public override void Disconnect()
        {
            _socket.Close();
        }

        public override void Send(RPCMessage message)
        {
            var buffer = Serialization.WriteBinary(message, BinarySerializationSettings.Latest);
            _socket.Send(buffer);
        }

    }
}