using CSharpUtil;
using CSharpUtil.Net;
using ProtoDataBuff;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Channels;
using System.Threading.Tasks;
using static System.Console;
using pb = global::Google.Protobuf;
using MultiDup;
namespace BattleRoom
{
    /// <summary>
    /// 房间状态
    /// </summary>
    enum RoomState
    {
        /// <summary>
        /// 开启状态(可以连接登入)
        /// </summary>
        Open,
        /// <summary>
        /// 已关闭(不可继续登录)
        /// </summary>
        Close,
    }

    enum TargetType
    {
        /// <summary>
        /// 所有
        /// </summary>
        All,
        /// <summary>
        /// 其他人
        /// </summary>
        Others,


    }

    class PropertyName
    {
        public const string Uid = nameof(Uid);
        public const string Name = nameof(Name);
        public const string Zoneid = nameof(Zoneid);
        public const string Hp = nameof(Hp);
        public const string MaxHp = nameof(MaxHp);
        public const string TotalDamage = nameof(TotalDamage);
    }

    /// <summary>
    /// 房间对象
    /// </summary>
    class Room
    {

        /// <summary>
        /// 房间状态字段
        /// </summary>
        public RoomState CurrentState = RoomState.Close;

        /// <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>
        public int Id { get; }

        /// <summary>
        /// 玩家id集合
        /// </summary>
        public List<string> PlayerUids = new List<string>();

        /// <summary>
        /// 战斗服务器端口
        /// </summary>
        public int BattleServerPort = 6006;
        /// <summary>
        /// 战斗服务器IP地址
        /// </summary>
        public string BattleServerIp = "192.168.10.17";

        /// <summary>
        /// 构造函数
        /// </summary> 
        public Room(int RoomId, IEnumerable<string> uids)
        {
            Id = RoomId;
            PlayerUids = uids.ToList();


            callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);
            callbacks.Add(eProtocalCommand.CsBtStatus, On_BtStatus);
            callbacks.Add(eProtocalCommand.CsBtPosition, On_BtPosition);
            callbacks.Add(eProtocalCommand.CsBtBroadCast, On_BtBroadCast);
            callbacks.Add(eProtocalCommand.CsBtPeopleList, On_PeopleList);
            var t = Task.Run(MsgLoop);
            Open();
        }


        void On_PeopleList(int peerId, sSocketData data)
        {
            var msg = CS_BT_PeopleList.Parser.ParseFrom(data._data);
            if (ClientPeers.TryGetValue(peerId, out var peer))
            {
                Console.WriteLine($"{msg.Uid} 在请求队友列表.");
                var info = new SC_BT_PeopleList() { NewerUid = "", Zoneid = msg.Zoneid };
                info.PlayerUids.AddRange(PlayerUids);
                peer.SendEvent(eProtocalCommand.ScBtPeopleList, info);
            }
        }


        void On_BtStatus(int peerId, sSocketData data)
        {
            var msg = CS_BT_Status.Parser.ParseFrom(data._data);
            if (ClientPeers.TryGetValue(peerId, out var peer))
            {
                var info = new SC_BT_Status() { PropertyName = msg.PropertyName, Value = msg.Value, SenderUid = msg.SenderUid, Zoneid = msg.Zoneid };
                this.Broadcast(TargetType.Others, eProtocalCommand.ScBtStatus, info);
            }
        }
        void On_BtPosition(int peerId, sSocketData data)
        {
            var msg = CS_BT_Position.Parser.ParseFrom(data._data);
            if (ClientPeers.TryGetValue(peerId, out var peer))
            {
                var info = new SC_BT_Position() { X = msg.X, Y = msg.Y, Z = msg.Z, SenderUid = msg.SenderUid, Zoneid = msg.Zoneid };
                this.Broadcast(TargetType.All, eProtocalCommand.ScBtPostion, info);
            }
        }
        void On_BtBroadCast(int peerId, sSocketData data)
        {
            var msg = CS_BT_BroadCast.Parser.ParseFrom(data._data);
            if (ClientPeers.TryGetValue(peerId, out var peer))
            {
                var info = new SC_BT_BroadCast() { Msg = msg.Msg, SenderUid = msg.SenderUid, Zoneid = msg.Zoneid };
                this.Broadcast(TargetType.Others, eProtocalCommand.ScBtBroadCast, info);
            }
        }

        void On_BtOver(int peerId, sSocketData data)
        {
            var msg = CS_BT_Over.Parser.ParseFrom(data._data);
            if (ClientPeers.TryGetValue(peerId, out var peer))
            {
                var info = new SC_BT_Over() { Msg = msg.Msg, SenderUid = msg.SenderUid, Zoneid = msg.Zoneid };
                this.Broadcast(TargetType.Others, eProtocalCommand.ScGameOver, info);
            }
        }



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




        #region 网络
        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
                {
                    // 未找到消息处理逻辑
                }
            }
        }
        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="targetType"></param>
        /// <param name="msgType"></param>
        /// <param name="msg"></param>
        private void Broadcast(TargetType targetType, eProtocalCommand msgType, pb::IMessage msg)
        {
            switch (targetType)
            {
                case TargetType.All:
                    this.ClientPeers.Values.ToList().ForEach(p => p.SendEvent(msgType, msg));
                    break;
                case TargetType.Others:
                    this.ClientPeers.Values.ToList().ForEach(p =>p.SendEvent(msgType, msg));
                    break;
            }

        }
        #endregion

        /// <summary>
        /// 开启
        /// </summary>
        public void Open()
        {

            this.CurrentState = RoomState.Open;
        }
        public void Close()
        {
            this.CurrentState = RoomState.Close;
            Task.Delay(TimeSpan.FromMinutes(1)).ContinueWith(t => Open());
        }


        private object lock_peers = new object();
        public void AddPeer(Peer p)
        {
            Console.WriteLine("加入房间ing");
            if (CurrentState == RoomState.Open)
            {
                lock (lock_peers)
                {
                    p.CurrentState = ClientState.InRoom;
                    p.room = this;
                    this.ClientPeers.Add(p.Id, p);
                }
            }
            else
            { 
                WriteLine("游戏结束2 // 这里不应该执行到!!!");
                p.SendEvent(eProtocalCommand.ScGameOver, new SC_MD_EnterRoom() { });
                p.Close();
            }
        }

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

    }

}
