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;

namespace BossServer.server
{
    /// <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 : Singleton<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);


        public string Name => DateTime.Now.ToString("yyyyMMddHH");

        public int MaxHp => Config.GameOnline ? 100000 : 10000;       // 初始血量10w


        /// <summary>
        /// boss集合
        /// </summary>
        private Dictionary<string, Boss> Boss_dict = new();


        /// <summary>
        /// 构造函数
        /// </summary> 
        public Room()
        {
            //this.Name = DateTime.Now.ToString("yyyyMMddHH");
            this.callbacks.Add(eProtocalCommand.CsLogin, On_Login);
            this.callbacks.Add(eProtocalCommand.CsReportDamage, On_ReportDamage);
            this.callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);
            this.callbacks.Add(eProtocalCommand.CsReportUserHp, On_ReportUserHp);
            var t = Task.Run(MsgLoop);
            Open();
        }
        /// <summary>
        /// 处理客户端上报玩家剩余血量逻辑
        /// </summary>
        /// <param name="peerId"></param>
        /// <param name="data"></param>
        void On_ReportUserHp(int peerId, sSocketData data)
        {
            var msg = CSReportUserHP.Parser.ParseFrom(data._data);
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                if (peer.Properties.ContainsKey(PropertyName.Hp))
                {
                    peer.Properties[PropertyName.Hp] = msg.UserHP;
                }
                else
                {
                    peer.Properties.Add(PropertyName.Hp, msg.UserHP);
                }
            }
        }

        /// <summary>
        /// 处理客户端登录请求
        /// </summary>
        void On_Login(int peerId, sSocketData data)
        {
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                var msg = CSEnterFight.Parser.ParseFrom(data._data);
                peer.Properties[nameof(msg.Uid)] = msg.Uid;

                peer.Properties[nameof(msg.Zoneid)] = msg.Zoneid;
                peer.Properties[PropertyName.Name] = msg.Name;
                peer.bossId = msg.BossId;
                lock (Boss_dict)
                {
                    var bossKey = $"{msg.Zoneid}-{msg.BossId}";
                    if (Boss_dict.TryGetValue(bossKey, out var boss))
                    {
                        if (boss.Ended)                                         // boss战已结束, 尚未重新开启
                        {
                            WriteLine("游戏结束1");
                            peer.SendEvent(eProtocalCommand.ScGameOver, new SCGameOver() { BossHp = boss.Hp, CountDown = boss.CountDownSecs });
                            peer.Close();
                        }
                        else
                        {
                            var peerHp = -1;                                    // 玩家血量, -1代表未初始化
                            var exists = boss.Peers.Where(kv => kv.Value.UID == peer.UID && kv.Value.zoneid == peer.zoneid);
                            if (exists.Count() < 1)
                            {
                                boss.Peers.Add(peerId, peer);
                            }
                            else
                            {                                                   // 已经进入到房间中过了
                                var oldPeer = exists.First().Value;
                                if (oldPeer.Properties.TryGetValue(PropertyName.Hp, out var hisHp))
                                {
                                    peerHp = int.Parse(hisHp.ToString());
                                    peer.Properties[PropertyName.Hp] = peerHp;
                                    Console.WriteLine($" 玩家记录血量:{peerHp} ");
                                }
                                boss.Peers.Remove(oldPeer.Id);
                                boss.Peers.Add(peerId, peer);
                            }
                            peer.SendEvent(eProtocalCommand.ScLogin, new SCEnterFight() { BossHp = boss.Hp, BossMaxHp = boss.MaxHp, UserHP = peerHp, CountDown = boss.CountDownSecs });
                            Console.WriteLine($"boss [{boss.ZoneId}] 已经初始化完毕, " + boss.Hp);
                        }
                    }
                    else                                                      // 初始化新的boss
                    {
                        Console.WriteLine($"初始化 boss [{msg.Zoneid}]");
                        var b = new Boss(msg.BossId, msg.Zoneid, MaxHp, BossSettle);
                        b.Peers.Add(peerId, peer);
                        Boss_dict.Add(b.UID, b);
                        peer.SendEvent(eProtocalCommand.ScLogin, new SCEnterFight() { BossHp = b.Hp, BossMaxHp = b.MaxHp, UserHP = -1, CountDown = b.CountDownSecs });
                    }
                }

            }
        }
        void BossSettle(Boss boss)
        {
            WriteLine($"结算Boss {boss.UID}");

            if (Boss_dict.ContainsKey(boss.UID))
            {
                var data = $"zoneid={boss.ZoneId}&bossid={boss.Id}";
                HttpHelper.Instance.Post(Config.Ins.SettleUrl, data);
                var t = Task.Delay(TimeSpan.FromSeconds(Config.Ins.CountDownTimes)).ContinueWith(t =>
                  {
                      lock (Boss_dict)
                      {
                          Boss_dict.Remove(boss.UID);
                      }
                  });
            }
        }

        /// <summary>
        /// 处理客户端上报伤害请求
        /// </summary>
        void On_ReportDamage(int peerId, sSocketData data)
        {

            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                var msg = CSFightReportDamage.Parser.ParseFrom(data._data);
                if (Boss_dict.TryGetValue(peer.BossKey, out var boss))
                {
                    boss.DamageQueue.Writer.WriteAsync(msg.Damage);
                    peer.AddDamage(msg.Damage);
                }
            }

        }
        /// <summary>
        /// 离开房间(战斗结束)
        /// </summary>
        /// <param name="data"></param>
        void On_Leave(int peerId, sSocketData data)
        {
            if (this.ClientPeers.TryGetValue(peerId, out var peer))
            {
                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
                {
                    // 未找到消息处理逻辑
                }
            }
        }
        /// <summary>
        /// 开启
        /// </summary>
        public void Open()
        {
            Boss_dict.Clear();
            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)
        {
            if (CurrentState == RoomState.Open)
            {
                lock (lock_peers)
                {
                    this.ClientPeers.Add(p.Id, p);
                }
            }
            else
            {

                WriteLine("游戏结束2 // 这里不应该执行到!!!");
                p.SendEvent(eProtocalCommand.ScGameOver, new SCGameOver() { BossHp = 0, CountDown = 9999 });
                p.Close();
            }
        }

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

    }

}
