using OnlineUserPool.Hander;
using OnlineUserPool.Model;
using OnlineUserPool.Unility;

using Serilog;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OnlineUserPool
{
    class Program
    {
        private static IPEndPoint serverIpEndPoint;
        private static UdpClient udpServer;
        private static List<HostModel> clients = new List<HostModel>();
        private static List<MsgModel> receiveMes = new List<MsgModel>();
        private static object locker = new object();
        public static System.Timers.Timer timer;
        private static MapRecordRankingHander mapRecordRankingHander;
        static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now.ToShortDateString());
            Console.WriteLine("加载日志组件");
            LogHelper.Init();
            Log.Information("日志组件加载完成");
            Log.Information("加载虚拟人物");
            mapRecordRankingHander = new MapRecordRankingHander();
            Log.Information("虚拟人物加载完成");
            Log.Information($"初始化连接,当前地址：{ConfigHelp.Ip}:{ConfigHelp.Port}");
            serverIpEndPoint = new IPEndPoint(IPAddress.Parse(ConfigHelp.Ip), ConfigHelp.Port);
            RunServer();
            Log.Information("服务启动成功");
            timer = new System.Timers.Timer(1000);
            timer.Elapsed += Timer_Elapsed;
            timer.AutoReset = true;
            timer.Start();
            Log.Information("等待连接");
            Console.ReadKey();
        }

        private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            NotifyClient();
        }

        private static void RunServer()
        {
            udpServer = new UdpClient(serverIpEndPoint.Port);
            uint IOC_IN = 0x80000000;
            uint IOC_VENDOR = 0x18000000;
            uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
            udpServer.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
            var remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        byte[] receiveBytes = udpServer.Receive(ref remoteIpEndPoint);
                        var returnData = Encoding.ASCII.GetString(receiveBytes);
                        var msg = Newtonsoft.Json.JsonConvert.DeserializeObject<MsgModel>(returnData);
                        lock (locker)
                        {
                            receiveMes.Add(msg);
                            Console.WriteLine($"本次接收:{ remoteIpEndPoint.Address.ToString() }:{ remoteIpEndPoint.Port }收到消息:{ returnData }");
                            if (!clients.Any(c => c.Equals(remoteIpEndPoint)))
                            {
                                clients.Add(new HostModel
                                {
                                    IPEndPoint = remoteIpEndPoint,
                                    LastActiveTime = DateTime.Now,
                                    RouteId = msg.RouteId,
                                    MemberId = msg.MemberId,
                                    ShowVirtual = msg.ShowVirtual
                                });
                            }
                            else
                            {
                                if (msg.CommandType == 0)
                                {
                                    var client = clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint));
                                    client.LastActiveTime = DateTime.Now;
                                    client.ShowVirtual = msg.ShowVirtual;
                                }
                            }
                            //if (timer.AutoReset == false)
                            //{
                            //    timer.AutoReset = true;
                            //}
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Error("RunServer：" + e.Message);
                    }
                }
            });
        }

        private static void NotifyClient()
        {
            try
            {
                lock (locker)
                {
                    //加入虚拟人物消息
                    var virtualData = mapRecordRankingHander.GetVirtualUserData();
                    Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "-当前在线人数:" + clients.Count + "-当前虚拟人数:" + virtualData.Count);
                    Console.WriteLine($"在线人：{Newtonsoft.Json.JsonConvert.SerializeObject(receiveMes)}\r\n虚拟人：{Newtonsoft.Json.JsonConvert.SerializeObject(virtualData)}");
                    receiveMes.AddRange(virtualData);
                    SendMessage(clients, receiveMes);
                    //移除下线的客户端
                    for (int i = 0; i < receiveMes.Count; i++)
                    {
                        if (receiveMes[i].exit)
                        {
                            var index = clients.FindIndex(n => n.MemberId == receiveMes[i].MemberId);
                            if (index > -1)
                            {
                                clients.RemoveAt(index);
                            }
                        }
                    }
                    receiveMes.Clear();//删除已经发送的数据
                    clients.RemoveAll(i => i.Expire);//移除5钟内连接不上的客户端
                }
                //更新虚拟人物信息
                Task.Run(() => { mapRecordRankingHander.RemoveEndAndAddNewVirtualUser(); });
            }
            catch (Exception e)
            {
                Log.Error("NotifyClient:" + e.Message);
            }
        }

        private static void SendMessage(List<HostModel> clients, List<MsgModel> msgModels)
        {
            string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(msgModels);
            var data = Encoding.ASCII.GetBytes(jsonString);
            foreach (var item in clients)
            {
                try
                {
                    udpServer.Send(data, data.Length, item.IPEndPoint);
                }
                catch (Exception e)
                {
                    Log.Error(item.IPEndPoint.ToString() + ":" + e.Message);
                }
            }
        }
    }
}
