using System;
using System.Collections.Generic;

using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Channels;
using ProtoDataBuff;

using CSharpUtil;
using MultiDup;

namespace BattleRoom
{

    /// <summary>
    /// 房间管理者, 负责 将连接上来的客户端转移到房间中
    /// </summary>
    internal class RoomManager : Singleton<RoomManager>
    {
        /// <summary>
        /// 服务器间的连接
        /// </summary>
        public ServerPeer ServerPeer;

        /// <summary>
        /// 客户端
        /// </summary>
        public Dictionary<int, Peer> ClientPeers = new Dictionary<int, Peer>();

        /// <summary>
        /// 消息分发
        /// </summary>
        private Dictionary<eProtocalCommand, Action<int, sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<int, sSocketData>>();

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


        /// <summary>
        /// 房间列表
        /// </summary>
        Dictionary<int, Room> roomDic = new Dictionary<int, Room>();


        public RoomManager()
        {
            this.callbacks.Add(eProtocalCommand.CsBtLogin, On_BtLogin);
            this.callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);

            var t = Task.Run(MsgLoop);

        }
        private object lock_peers = new object();
        public void AddPeer(Peer p)
        {
            lock (lock_peers)
            {
                this.ClientPeers.Add(p.Id, p);
                Console.WriteLine(p.Id + " 连接上来了!");
            }

        }
        public void RemovePeer(int peerId)
        {
            lock (lock_peers)
            {
                if (this.ClientPeers.ContainsKey(peerId))
                {
                    this.ClientPeers.Remove(peerId);
                }
            }
        }

        public void OnNewPeerConnected(Peer peer)
        {
            AddPeer(peer);
        }

        /// <summary>
        /// 进入大厅(登陆自己的uid)
        /// </summary>
        /// <param name="data"></param>
        void On_BtLogin(int peerId, sSocketData data)
        {
            var msg = CS_BT_Login.Parser.ParseFrom(data._data);
            Console.WriteLine("登录逻辑");
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                Console.WriteLine("寻找对应的房间");
                roomDic.Values.ToList().ForEach(r =>
                {
                    if (r.PlayerUids.Contains(msg.Uid))
                    {
                        peer.room = r;               // 设置自己的room
                        r.AddPeer(peer);
                        Console.WriteLine("加入对应的房间");
                    }
                });
                if (null == peer.room)
                {
                    Console.WriteLine("未找到对应的房间");
                    peer.SendEvent(eProtocalCommand.ScBtLogin, new SC_BT_Login() { Msg = "未找到对应房间!" });
                }
                else
                {
                    peer.Properties.Add(PropertyName.Uid, msg.Uid);
                    peer.Properties.Add(PropertyName.Zoneid, msg.Zoneid);
                    peer.CurrentState = ClientState.InGame;
                    peer.SendEvent(eProtocalCommand.ScBtLogin, new SC_BT_Login() { Msg = peer.room.Id.ToString() });

                }

            }
        }



        /// <summary>
        /// 创建一个房间(副本)
        /// </summary>
        /// <param name="data"></param>
        public void CreateRoom(sSocketData data)
        {
            Console.WriteLine("接收到创建房间指令!");
            var msg = SS_CreateBattleServer.Parser.ParseFrom(data._data);

            var room = new Room(msg.RoomId, msg.PlayerUids);
            roomDic.Add(room.Id, room);

            ServerPeer.SendEvent(eProtocalCommand.SsCreateBattleRoomOk, new SS_CreateBattleServerOK() { });
            // todo: 建立玩家列表, 当玩家登录进来以后, 将其连接转入房间

        }

        /// <summary>
        /// 离开房间(战斗结束)
        /// </summary>
        /// <param name="data"></param>
        void On_Leave(int peerId, sSocketData data)
        {
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                peer.SendEvent(eProtocalCommand.ScMdLeaveRoom, new SC_MD_LeaveRoom() { });
                peer.Close();
            }
        }

        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
                {
                    // 未找到消息处理逻辑
                }
            }
        }
    }
}
