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;

namespace MultiDup
{
    /// <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);

        // 房间计数器
        private static int _roomIdCounter = 0;
        /// <summary>
        /// 房间编号
        /// </summary>
        public int Id { get; }

        public int mapId { get; }

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

        /// <summary>
        /// 构造函数
        /// </summary> 
        public Room(int mapid)
        {
            mapId = mapid;
            Id = _roomIdCounter++;

            callbacks.Add(eProtocalCommand.CsMdBeginDup, On_Start); 
            callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);

            var t = Task.Run(MsgLoop);
            Open();
        }

        /// <summary>
        /// 开始游戏 
        /// </summary>
        /// <param name="data"></param>
        void On_Start(int peerId, sSocketData data)
        {
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                if (null != Program.serverPeer)                                                      // battleServer创建对应的房间
                {
                    var sendmsg = new SS_CreateBattleServer() { RoomId = this.Id };
                    this.ClientPeers.Values.ToList().ForEach(p =>
                    {
                        sendmsg.PlayerUids.Add(p.UID);
                    });
                    Program.serverPeer.SendEvent(eProtocalCommand.SsCreateBattleRoom, sendmsg);     // 向battle服务器发送创建房间的指令
                    Console.WriteLine("发送创建房间指令");
                }
                else
                {
                    Console.WriteLine(" 没有可用的battle服务器! ");
                }
                Broadcast(TargetType.All, eProtocalCommand.ScMdBeginDup, new SC_MD_BeginDup() {  Mapid = this.mapId, Battleserver = this.BattleServerIp, BattleServerPort = this.BattleServerPort });
            }
        }


        /// <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:
                    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());
            Lobby.Instance.RemoveRoom(this.Id);

        }


        private object lock_peers = new object();
        public void AddPeer(Peer p)
        {
            if (CurrentState == RoomState.Open)
            {
                lock (lock_peers)
                {
                    p.CurrentState = ClientState.InRoom;
                    p.room = this;
                    this.ClientPeers.Add(p.Id, p);
                }
                var list = new SC_MD_EnterRoom() {  Ip = BattleServerIp,Port= BattleServerPort, Uid = p.UID, Zoneid = p.zoneid };

                ClientPeers.Values.ToList().ForEach(c => list.PlayerUids.Add(c.UID));
                Broadcast(TargetType.All, eProtocalCommand.ScMdEnterRoom, list);
                p.OnSocketDisconnected = () =>
                {
                    Lobby.Instance.RemovePeer(p.Id);
                    RemovePeer(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);
                }
                if (ClientPeers.Count == 0)
                {
                    this.Close();
                }
            }
        }
        public void RemovePeer(int peerId)
        {
            lock (lock_peers)
            {
                if (this.ClientPeers.ContainsKey(peerId))
                {
                    this.ClientPeers.Remove(peerId);
                }
            }
        }

    }

}
