using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Handlers.Timeout;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using DotNettyFrom.common;
using DotNettyFrom.config;
using DotNettyFrom.generatecmd;
using DotNettyFrom.util;

namespace DotNettyFrom.netty
{
    public class NettyClient
    {
        private MultithreadEventLoopGroup _group;
        private NettyClientHandler _clientHandler;
        private static string LoginCmd = null;

        public void StartNetty(string host, int port, string loginCmd)
        {
            LoginCmd = loginCmd;
            IPAddress hostIp = IPAddress.Parse(host);
            RunClientAsync(hostIp, port);
            DataModel.ReceCollection.Add(new UIInfoModel("StartNetty:开始尝试连接").setSendType(SystemConfig.DebugType));
        }

        private async void RunClientAsync(IPAddress HostIP, int Port)
        {
            _group = new MultithreadEventLoopGroup();
            var bootstrap = new Bootstrap();
            bootstrap
                .Group(_group)
                .Channel<TcpSocketChannel>()
                .Option(ChannelOption.TcpNodelay, true)
                .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                {
                    IChannelPipeline pipeline = channel.Pipeline;
                    pipeline.AddLast(new LengthFieldBasedFrameDecoder(ushort.MaxValue,
                        SystemConfig.LengthFieldOffset,
                        SystemConfig.LengthFieldLength,
                        SystemConfig.LengthAdjustment,
                        SystemConfig.InitialBytesToStrip));
                    pipeline.AddLast(new IdleStateHandler(SystemConfig.ReaderIdleTimeSeconds,
                        SystemConfig.WriterIdleTimeSeconds,
                        SystemConfig.AllIdleTimeSeconds));
                    _clientHandler = new NettyClientHandler();
                    pipeline.AddLast(_clientHandler);
                }));
            try
            {
                await bootstrap.ConnectAsync(new IPEndPoint(HostIP, Port));
            }
            catch (Exception e)
            {
                //连接出错,服务器没开启....
                //Console.WriteLine(e);
                DataModel.ReceCollection.Add(new UIInfoModel("远程服务器连接失败." + e.Message).setAction(-1)
                    .setSendType(SystemConfig.DebugType));
                await _group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
            }
        }


        public void SendData(string hex)
        {
            if (NettyClientHandler.Context.Channel.Active)
            {
                IByteBuffer msg = AryUtil.Hex2IByteBuffer(hex);
                Console.WriteLine(hex);
                NettyClientHandler.Context.WriteAndFlushAsync(msg);
                DataModel.ReceCollection.Add(new UIInfoModel("发送", hex).setSendType(SystemConfig.SendType));
            }
            else
            {
                DataModel.ReceCollection.Add(new UIInfoModel("SendData:连接已经断开").setSendType(SystemConfig.DebugType));
            }
        }


        public void StopNetty()
        {
            NettyClientHandler.Context?.Channel.CloseAsync();
            _group?.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
            _group = null;
            NettyClientHandler.Context = null;
            _clientHandler = null;
            DataModel.ReceCollection.Add(new UIInfoModel("StopNetty:停止连接"));
        }


        public class NettyClientHandler : ChannelHandlerAdapter
        {
            internal static IChannelHandlerContext Context;

            public override void ChannelActive(IChannelHandlerContext context)
            {
                Context = context;
                DataModel.ReceCollection.Add(new UIInfoModel("ChannelActive:连接成功").setAction(1)
                    .setSendType(SystemConfig.DebugType));

                if (LoginCmd != null)
                {
                    //发送登录指令
                    IByteBuffer cmd = AryUtil.Hex2IByteBuffer(LoginCmd);
                    context.WriteAndFlushAsync(cmd);
                    DataModel.ReceCollection.Add(new UIInfoModel("发送登录", LoginCmd)
                        .setAction(1).setSendType(SystemConfig.SendType));
                }
            }


            public override void ChannelRead(IChannelHandlerContext context, object message)
            {
                if (message is IByteBuffer buffer)
                {
                    string recCmd = AryUtil.ByteBuffer2Hex(buffer);

                    Console.WriteLine("收到:" + recCmd);

                    string cmd = CmdGenetor.Genetor?.GetReplyCmd(recCmd);
                    if (cmd != null)
                    {
                        IByteBuffer replyBuffer = AryUtil.Hex2IByteBuffer(cmd);
                        context.WriteAndFlushAsync(replyBuffer);
                    }
                }
                else
                {
                    Console.WriteLine("Other ChannelRead");
                }
            }


            public override void UserEventTriggered(IChannelHandlerContext context, object evt)
            {
                if (SystemConfig.OpenHeartBeat)
                {
                    IdleStateEvent state = (IdleStateEvent) evt;


                    if (state == IdleStateEvent.ReaderIdleStateEvent)
                    {
                    }
                    else if (state == IdleStateEvent.WriterIdleStateEvent)
                    {
                        string hb = CmdGenetor.Genetor.GetHeartbeat();
                        context.Channel.WriteAndFlushAsync(AryUtil.Hex2IByteBuffer(hb));
                        Console.WriteLine("发送心跳:" + hb + ".log=" + SystemConfig.IsLogHeartBeatInfo);
                        if (SystemConfig.IsLogHeartBeatInfo)
                        {
                            DataModel.ReceCollection.Add(new UIInfoModel("发送心跳", hb).setSendType(SystemConfig.SendType));
                        }
                    }
                }
            }

            public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
            {
                base.ExceptionCaught(context, exception);
                Console.WriteLine(exception.Message);
                DataModel.ReceCollection.Add(new UIInfoModel("ExceptionCaught:" + exception.Message).setAction(3)
                    .setSendType(SystemConfig.DebugType));
            }

            public override void ChannelInactive(IChannelHandlerContext context)
            {
                base.ChannelInactive(context);
                DataModel.ReceCollection.Add(new UIInfoModel("ChannelInactive:" + context.Channel.RemoteAddress)
                    .setAction(2).setSendType(SystemConfig.DebugType));
            }
        }
    }
}