using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;

using pb = global::Google.Protobuf;

namespace BossServer.server
{

    /// <summary>
    /// Boss对象
    /// </summary>
    class Boss
    {
        /// <summary>
        /// 当前血量
        /// </summary>
        public volatile int Hp;
        /// <summary>
        /// 最大血量
        /// </summary>
        public readonly int MaxHp;

        public int CountDownSecs;

        /// <summary>
        /// boss ZoneID
        /// </summary>
        public int ZoneId;
        /// <summary>
        /// boss id (大小boss,现在只有1,2)
        /// </summary>
        public int Id;

        /// <summary>
        /// 唯一id
        /// </summary>
        public string UID => $"{ZoneId}-{Id}";

        public Dictionary<int, Peer> Peers;

        public Channel<int> DamageQueue;


        private Action<Boss> _Settle;

        private readonly Timer timer;

        /// <summary>
        /// 倒计时模块
        /// </summary>
        /// <param name="stateObject"></param>
        private void OnTimer(object stateObject)
        {
            CountDownSecs--;
        }

        /// <summary>
        /// 战斗结束
        /// </summary>
        public bool Ended { get; private set; } = false;

        public Boss(int id, int zoneid, int maxHp, Action<Boss> Settle)
        {
            this.Id = id;
            this.ZoneId = zoneid;
            this.Hp = this.MaxHp = maxHp;
            this.CountDownSecs = Config.Ins.CountDownTimes;
            var roomName = Room.Instance.Name ?? "Room";
            var redis_key = MemKey_Game.BossFight_Damage_byDateHour_zset(Convert.ToInt32(ZoneId), Id, roomName);
            var rdb = Redis.Ins.GetDatabase(0);
            rdb.KeyDelete(redis_key);
            this.Peers = new Dictionary<int, Peer>();
            this.DamageQueue = Channel.CreateBounded<int>(100);
            this._Settle = Settle;
            var t = Task.Run(Damage);
            this.timer = new Timer(OnTimer, null, 0, 1000);       // 1秒1次
            var end = Task.Delay(TimeSpan.FromSeconds(Config.Ins.CountDownTimes)).ContinueWith(t =>      // 10分钟结束战斗
            {
                this.Settle();
            });
        }





        private async Task<int> Damage()
        {
            while (Hp > 0)
            {
                var damage = await DamageQueue.Reader.ReadAsync();
                Hp += damage;
                if (Hp < 0)
                {
                    Hp = 0;
                }
                CheckHp();
            }
            return 0;
        }
        public void CheckHp()
        {
            if (Hp > 0)
            {
                BroadUpdate();
            }
            else
            {
                Settle();
            }
        }

        private void Settle()
        {
            if (!this.Ended)
            {
                this.Ended = true;
                this.CountDownSecs = Config.Ins.CountDownTimes;
                BroadGameOver();
                this?._Settle(this);

            }
        }

        private void BroadGameOver()
        {

            Console.WriteLine("游戏结束1");
            this.Broadcast(TargetType.All, eProtocalCommand.ScGameOver, new SCGameOver() { BossHp = this.Hp, CountDown = this.CountDownSecs });
            this.Peers.Values.ToList().ForEach(p => p.Close());
        }

        private void BroadUpdate()
        {
            this.Broadcast(TargetType.All, eProtocalCommand.ScUpdateProperties, new SCUpdateProperties() { BossMaxHp = this.MaxHp, BossHp = this.Hp, CountDown = this.CountDownSecs });
        }

        /// <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.Peers.Values.ToList().ForEach(p => p.SendEvent(msgType, msg));
                    break;
                case TargetType.Others:
                    break;
            }

        }
    }
}
