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;
using System.Threading.Channels;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ProtoDataBuff;
using ChatServer.server;
using Chat;
namespace ChatServer
{
    class Program
    {
        const int port = 6000;                                                  // 端口号（用来监听的）
        static Socket SocketWatch = null;                                       // 创建一个和客户端通信的套接字
        /// <summary>
        /// peer管理集合
        /// </summary>
        static public Dictionary<string, Peer> Peers = new Dictionary<string, Peer>();
        /// <summary>
        /// 消息分发
        /// </summary>
        private static Dictionary<eProtocalCommand, Action<string, sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<string, sSocketData>>();
        static void Main(string[] args)
        {
            IPAddress ip = IPAddress.Any;
            IPEndPoint ipe = new IPEndPoint(ip, port);                         //将IP地址和端口号绑定到网络节点point上  

            //  callbacks.Add(eProtocalCommand.CsChatLogin, On_Login);             // 绑定处理逻辑
            callbacks.Add(eProtocalCommand.CsChatSendMsg, On_SendMessage);     // 绑定处理逻辑

            //定义一个套接字用于监听客户端发来的消息，包含三个参数（IP4寻址协议，流式连接，Tcp协议）  
            SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketWatch.Bind(ipe);                                             // 监听绑定的网络节点           
            SocketWatch.Listen(20);                                            // 将套接字的监听队列长度限制为20    

            Console.WriteLine("开启监听......");
            Console.WriteLine("ctrl + c 退出程序......");
            Task.Run(MsgLoop);
            Task.Run(WatchConnecting).Wait();
            SocketWatch.Close();
        }

        internal static void AddPeer(Peer p)
        {
            lock (Peers)
            {
                Peers.Add(p.Key, p);
            }
        }
        internal static void RemovePeer(string key)
        {
            lock (Peers)
            {
                Peers.Remove(key);
            }
        }


        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="peerId"></param>
        /// <param name="data"></param>
        static void On_SendMessage(string peerKey, sSocketData data)
        {
            if (Peers.TryGetValue(peerKey, out Peer p))
            {
                var msg = CS_ChatSendMsg.Parser.ParseFrom(data._data);
                if (null != msg &&  msg.Msg.Trim().Length>0)
                {
                    var rdb = Redis.Ins.GetDatabase(0);
                    var sd = new SC_ChatNewMsg() { FromChannel = msg.ToChannel, SenderName = p.Name, Msg = msg.Msg, SenderUid = p.UID };
                    switch (msg.ToChannel)
                    {
                        case ChatChannel.System:    // 这个一般是客户端生成的, 除非是GM号,一般人发送这种消息拒绝转发.
                            if (rdb.HashExists(MemKey_Cfg.GM_uids_hash, p.UID))
                            {
                                Peers.Values.ToList().ForEach(_p => _p.SendEvent(eProtocalCommand.ScChatNewMsg, sd));
                            }
                            else
                            {
                                Console.WriteLine($"非GM用户({p.UID})发送了系统消息转发请求!");
                            }
                            break;
                        case ChatChannel.World:
                            Peers.Values.ToList().ForEach(_p => _p.SendEvent(eProtocalCommand.ScChatNewMsg, sd));
                            break;
                        case ChatChannel.Guild:
                            if (rdb.HashExists(MemKey_User.Guild(p.UID, p.zoneid), "guildId"))
                            {
                                var a = rdb.HashGet(MemKey_User.Guild(p.UID, p.zoneid), "guildId").ToString();
                                var guildId = int.Parse(a);
                                if (guildId > 0)
                                {
                                    JArray jArray = JArray.Parse(rdb.HashGet(MemKey_Game.Guild(p.zoneid, guildId), "members").ToString());
                                    if (jArray.Count > 0)
                                    {
                                        var keys = from j in jArray select j.ToString() + ":" + p.zoneid;
                                        Peers.Where(kv => keys.Contains(kv.Key)).ToList().ForEach(kv => kv.Value.SendEvent(eProtocalCommand.ScChatNewMsg, sd));
                                    }

                                }
                                else
                                {
                                    Console.WriteLine($"找不到用户({p.UID})的公会信息");
                                }
                            }
                            else
                            {
                                Console.WriteLine($"找不到用户({p.UID})的公会信息");
                            }

                            break;

                        case ChatChannel.Single:
                            Peers.Values.Where(peer =>peer.Name == msg.ToNickName).ToList().ForEach(_p => _p.SendEvent(eProtocalCommand.ScChatNewMsg, sd));
                            break;
                        default:
                            Console.WriteLine("chat:未知的发送目标");
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// 监听客户端发来的请求  
        /// </summary>
        async static Task WatchConnecting()
        {
            while (true)                                                                 // 持续不断监听客户端发来的请求     
            {
                Socket connection;
                try
                {
                    connection = await SocketWatch.AcceptAsync();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);                                       // 提示套接字监听异常     
                    break;
                }

                var p = new Peer(connection);

            }
        }



        /// <summary>
        /// 客户端消息队列
        /// </summary>
        public static Channel<KeyValuePair<string, sSocketData>> MsgChannel = Channel.CreateBounded<KeyValuePair<string, sSocketData>>(1000);

        static async void MsgLoop()
        {
            while (true)
            {
                var msg = await MsgChannel.Reader.ReadAsync();
                if (callbacks.ContainsKey(msg.Value._protocallType))
                {
                    callbacks[msg.Value._protocallType](msg.Key, msg.Value);
                }
                else
                {
                    // 未找到消息处理逻辑
                }
            }
        }
    }
}
