using common.libs;
using common.libs.extends;
using System.Buffers;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.server.service
{
    /// 
    /// 连接对象
    /// 
    public interface IConnection
    {
        public string Name{ get; set; }
        /// 
        /// 
        /// 已连接
        /// 
        public bool Connected { get; }
        public IPEndPoint Address { get; }
        #region 接收数据
        /// 
        /// 请求数据包装对象
        /// 
        public MessageRequestWrap ReceiveRequestWrap { get; }
        /// 
        /// 回复数据包装对象
        /// 
        public MessageResponseWrap ReceiveResponseWrap { get; }
        /// 
        /// 接收到的原始数据
        /// 
        public Memory ReceiveData { get; set; }
        #endregion
        /// 
        /// 发送
        /// 
        /// 
        /// 
        public Task Send(ReadOnlyMemory data, bool unconnectedMessage = false);
        /// 
        /// 发送
        /// 
        /// 
        /// 
        /// 
        public Task Send(byte[] data, int length, bool unconnectedMessage = false);
        /// 
        /// 销毁
        /// 
        public void Disponse();
        #region 回复消息相关
        public Memory ResponseData { get; }
        public void Write(Memory data);
        public void Write(ulong num);
        public void Write(ushort num);
        public void Write(ushort[] nums);
        /// 
        /// 英文多用这个
        /// 
        /// 
        public void WriteUTF8(string str);
        /// 
        /// 中文多用这个
        /// 
        /// 
        public void WriteUTF16(string str);
        /// 
        /// 归还池
        /// 
        public void Return();
        #endregion
        public Task WaitOne();
        public void Release();
    }
    public abstract class Connection : IConnection
    {
        public Connection()
        {
        }
        public string Name { get; set; }
        /// 
        /// 已连接
        /// 
        public virtual bool Connected => false;
        /// 
        /// 地址
        /// 
        public IPEndPoint Address { get; protected set; }
        #region 接收数据
        /// 
        /// 接收请求数据
        /// 
        public MessageRequestWrap ReceiveRequestWrap { get; set; }
        /// 
        /// 接收回执数据
        /// 
        public MessageResponseWrap ReceiveResponseWrap { get; set; }
        /// 
        /// 接收数据
        /// 
        public Memory ReceiveData { get; set; }
        #endregion
        #region 回复数据
        public Memory ResponseData { get; private set; }
        private byte[] responseData;
        private int length = 0;
        public void Write(Memory data)
        {
            ResponseData = data;
        }
        public void Write(ulong num)
        {
            length = 8;
            responseData = ArrayPool.Shared.Rent(length);
            num.ToBytes(responseData);
            ResponseData = responseData.AsMemory(0, length);
        }
        public void Write(ushort num)
        {
            length = 2;
            responseData = ArrayPool.Shared.Rent(length);
            num.ToBytes(responseData);
            ResponseData = responseData.AsMemory(0, length);
        }
        public void Write(ushort[] nums)
        {
            length = nums.Length * 2;
            responseData = ArrayPool.Shared.Rent(length);
            nums.ToBytes(responseData);
            ResponseData = responseData.AsMemory(0, length);
        }
        /// 
        /// 英文多用这个
        /// 
        /// 
        public void WriteUTF8(string str)
        {
            var span = str.AsSpan();
            responseData = ArrayPool.Shared.Rent((span.Length + 1) * 3 + 8);
            var memory = responseData.AsMemory();
            int utf8Length = span.ToUTF8Bytes(memory.Slice(8));
            span.Length.ToBytes(memory);
            utf8Length.ToBytes(memory.Slice(4));
            length = utf8Length + 8;
            ResponseData = responseData.AsMemory(0, length);
        }
        /// 
        /// 中文多用这个
        /// 
        /// 
        public void WriteUTF16(string str)
        {
            var span = str.GetUTF16Bytes();
            length = span.Length + 4;
            responseData = ArrayPool.Shared.Rent(length);
            str.Length.ToBytes(responseData);
            span.CopyTo(responseData.AsSpan(4));
            ResponseData = responseData.AsMemory(0, length);
        }
        /// 
        /// 归还池
        /// 
        public void Return()
        {
            if (length > 0 && ResponseData.Length > 0)
            {
                ArrayPool.Shared.Return(responseData);
            }
            ResponseData = Helper.EmptyArray;
            responseData = null;
            length = 0;
        }
        #endregion
        /// 
        /// 发送
        /// 
        /// 
        /// 
        public abstract Task Send(ReadOnlyMemory data, bool logger = false);
        /// 
        /// 发送
        /// 
        /// 
        /// 
        /// 
        public abstract Task Send(byte[] data, int length, bool logger = false);
        /// 
        /// 销毁
        /// 
        public virtual void Disponse()
        {
            try
            {
                if (Semaphore != null)
                {
                    if (locked)
                    {
                        locked = false;
                        Semaphore.Release();
                    }
                    Semaphore.Dispose();
                }
                Semaphore = null;
            }
            catch (Exception ex)
            {
                Logger.Instance.Error(ex);
            }
            //ReceiveRequestWrap = null;
            //ReceiveResponseWrap = null;
        }
        SemaphoreSlim Semaphore = new SemaphoreSlim(1);
        bool locked = false;
        public virtual async Task WaitOne()
        {
            try
            {
                if (Semaphore != null)
                {
                    locked = true;
                    await Semaphore.WaitAsync();
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Error(ex);
            }
        }
        public virtual void Release()
        {
            try
            {
                if (Semaphore != null)
                {
                    locked = false;
                    Semaphore.Release();
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Error(ex);
            }
        }
    }
    public sealed class TcpConnection : Connection
    {
        public TcpConnection(Socket tcpSocket) : base()
        {
            TcpSocket = tcpSocket;
            IPEndPoint address = TcpSocket.RemoteEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
            if (address.Address.AddressFamily == AddressFamily.InterNetworkV6 && address.Address.IsIPv4MappedToIPv6)
            {
                address = new IPEndPoint(new IPAddress(address.Address.GetAddressBytes()[^4..]), address.Port);
            }
            Address = address;
        }
        /// 
        /// 已连接
        /// 
        public override bool Connected => TcpSocket != null && TcpSocket.Connected;
        /// 
        /// socket
        /// 
        public Socket TcpSocket { get; private set; }
        /// 
        /// 发送
        /// 
        /// 
        /// 
        public override async Task Send(ReadOnlyMemory data, bool unconnectedMessage = false)
        {
            if (Connected)
            {
                try
                {
                    await TcpSocket.SendAsync(data, SocketFlags.None);
                    //SentBytes += (ulong)data.Length;
                    return true;
                }
                catch (Exception ex)
                {
                    Disponse();
                    if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
                        Logger.Instance.Error(ex);
                }
            }
            return false;
        }
        /// 
        /// 发送
        /// 
        /// 
        /// 
        /// 
        public override async Task Send(byte[] data, int length, bool unconnectedMessage = false)
        {
            return await Send(data.AsMemory(0, length), unconnectedMessage);
        }
        /// 
        /// 销毁
        /// 
        public override void Disponse()
        {
            base.Disponse();
            if (TcpSocket != null)
            {
                TcpSocket.SafeClose();
                TcpSocket.Dispose();
            }
        }
    }
}