using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNetty.Buffers;
using DotNetty.Transport.Channels;
using Team.Communicate.Data;
using Team.Communicate.EventArg;
using Team.Utility;

namespace Team.Communicate.Handlers
{
    public class TelnetServerHandler : ChannelHandlerAdapter// SimpleChannelInboundHandler<string>
    {
        public event EventHandler<TcpStateEventArgs> ConnectionEvent;
        private List<string> UseUnRegisterKeys = new();
        private readonly ConcurrentDictionary<string, Func<string, IChannelHandlerContext, ValueTask<string>>> _registerCenterCollection;
        public Action<string, IChannelHandlerContext> UseUnRegisterAction;
        public Encoding Encoding { get; set; }
        public string _endWith{ get; private set; }
        public TelnetServerHandler()
        {
            _registerCenterCollection = new ConcurrentDictionary<string, Func<string, IChannelHandlerContext, ValueTask<string>>>();
        }
        internal void SetEncoding(Encoding encoding)
        {
            Encoding = encoding;
        }
        public void Register(string id, Func<string, IChannelHandlerContext, ValueTask<string>> func)
        {
            if (_registerCenterCollection.ContainsKey(id))
            {
                _registerCenterCollection[id] = func;
                return;
            }
            _registerCenterCollection.TryAdd(id, func);
        }
        public void UnRegister(string id)
        {
            if (!_registerCenterCollection.ContainsKey(id)) return;
            _registerCenterCollection.TryRemove(id, out var func);
        }

        public void ClearAllRegister()
        {
            _registerCenterCollection.Clear();
        }
        public override void ChannelActive(IChannelHandlerContext context)
        {
            base.ChannelActive(context);
            var iPEndPoint = (IPEndPoint) context.Channel.RemoteAddress;
            var ipAddress = iPEndPoint.Address;
            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
            {
                ipAddress = ipAddress.MapToIPv4();
            }

            var port = iPEndPoint.Port;
            OnConnectionChanged(ipAddress.ToString(), port, true);
        }
        /// <summary>
        /// use unregister message 
        /// </summary>
        internal void SetUseUnRegisterKeys(List<string> keys)
        {
            UseUnRegisterKeys = keys;
        }

        public override void ChannelInactive(IChannelHandlerContext context)
        {
            base.ChannelInactive(context);
            var iPEndPoint = (IPEndPoint)context.Channel.RemoteAddress;
            var ipAddress = iPEndPoint.Address;
            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
            {
                ipAddress = ipAddress.MapToIPv4();
            }
            var port = iPEndPoint.Port;
            OnConnectionChanged(ipAddress.ToString(), port, false);
        }

        internal void SetEndWith(string endWith)
        {
            _endWith = endWith;
        }
       
        public async override void ChannelRead(IChannelHandlerContext context, object data)
        {
            //base.ChannelRead(ctx, msg);
            string msg = string.Empty;
           
            if (data is IByteBuffer buffer)
            {
                LogUtil.WriteInfo("Received from client: " + buffer.ToString(Encoding));
                msg = buffer.ToString(Encoding);
            }
            var ipAddress = ((IPEndPoint)context.Channel.RemoteAddress).Address;
            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
            {
                ipAddress = ipAddress.MapToIPv4();
            }
            LogUtil.WriteInfo($"客户端{ipAddress}发生消息:{msg}");
            msg = msg.Replace("\0", string.Empty);
            if (!context.Channel.Active)
            {
                LogUtil.WriteInfo($"客户端{ipAddress}断开未完成对话");
                return;
            }

            if (!_registerCenterCollection.ContainsKey(msg))
            {
                foreach (var key in UseUnRegisterKeys)
                {
                    if (msg.Contains(key))
                    {
                        LogUtil.WriteInfo($"客户端{ipAddress}发送需要使用的未注册消息");
                        UseUnRegisterAction?.BeginInvoke(msg, context, null, null);
                        return;
                    }
                }
                LogUtil.WriteInfo($"客户端{ipAddress}发送未注册消息");
                try
                {
                    var stringBuilder = new StringBuilder();
                    stringBuilder.Append("NotRegisterMessage,");
                    stringBuilder.Append(msg);
                    stringBuilder.Append(_endWith);
                    var bytes= Encoding.GetBytes(stringBuilder.ToString());
                    var sendBytes = Unpooled.Buffer(256);
                    sendBytes.WriteBytes(bytes);
                    await context.WriteAndFlushAsync(sendBytes);
                }
                catch (Exception e)
                {
                    LogUtil.WriteInfo("发送数据时发生了错误" + e);
                }
                return;
            }
            LogUtil.WriteInfo("等待处理消息");
            var invoker = _registerCenterCollection[msg];
            invoker.BeginInvoke(msg, context, async obj =>
            {
                string response = await invoker.EndInvoke(obj);
                if (string.IsNullOrEmpty(msg))
                {
                    response = "Please type something.";
                }
                Thread.Sleep(10000);
                response += _endWith;
                var bytes1 = Encoding.GetBytes(response);
                var sendBytes1 = Unpooled.Buffer(5);
                sendBytes1.WriteBytes(bytes1);
                await context.WriteAndFlushAsync(sendBytes1);
            }, context);
        }

        public override void Read(IChannelHandlerContext context)
        {
            base.Read(context);
        }
        public override void ChannelReadComplete(IChannelHandlerContext context)
        {
            try
            {
                context.Flush();
                base.ChannelReadComplete(context);
            }
            catch (Exception e)
            {
                LogUtil.WriteInfo(e.StackTrace);
            }
           
        }

        public async override void ExceptionCaught(IChannelHandlerContext context, Exception e)
        {
            LogUtil.WriteInfo(e.StackTrace);
            try
            {
                
                await context.CloseAsync();
            }
            catch (Exception se)
            {
                LogUtil.WriteInfo(se.StackTrace);
            }
          
        }


        public override void ChannelUnregistered(IChannelHandlerContext context)
        {
            base.ChannelUnregistered(context);
        }

        private void OnConnectionChanged(string ip, int port, bool connected)
        {
            var args = new TcpStateEventArgs(new TcpConnection(ip, port)
            {
                Connected = connected
            });
            ConnectionEvent?.Invoke(this, args);
        }

        public override bool IsSharable => true;
    }

}