using System;
using System.Collections.Generic;
namespace Fort23.Core
{
    public enum TimerType
    {
        None,
        Wait, // 等待
        Count, // 次数
    }
    public class TimerEntity : Entity
    {
        public TimerType timerType;
        /// 
        /// 计时时间,毫秒
        /// 
        public long time;
       
        /// 
        /// 完成回调
        /// 
        public object callback1;
        /// 
        /// 次数
        ///  
        public int count;
        /// 
        /// 针对多次的,每次Hit回调
        /// 
        public object callback2;
        [CustomMethod(CustomMethodType.Awake)]
        public void Awake(TimerType timerType, long time, object callback1, int count, object callback2)
        {
            this.timerType = timerType;
            this.time = time;
            this.callback1 = callback1;
            this.count = count;
            this.callback2 = callback2;
        }
        [CustomMethod(CustomMethodType.Destroy)]
        public void Destroy()
        {
            this.timerType = TimerType.None;
            this.time = 0;
            this.callback1 = null;
            this.count = 0;
            this.callback2 = null;
        }
    }
    public class TimerComponent : Entity
    {
        public static TimerComponent Instance { get; set; }
        /// 
        /// key: time, value: timer id
        /// 
        private readonly MultiMap _timeID = new MultiMap();
        private readonly Queue _timeOutTime = new Queue();
        private readonly Queue _timeOutTimerIds = new Queue();
        // 记录最小时间,不用每次都去MultiMap取第一个值
        private long _minTime;
        [CustomMethod(CustomMethodType.Awake)]
        public void Awake()
        {
            Instance = this;
        }
        [CustomMethod(CustomMethodType.Update)]
        public void Update()
        {
            
           
            if (this._timeID.Count == 0)
            {
                return;
            }
            long timeNow = TimeHelper.ServerNow();
            if (timeNow < this._minTime)
            {
                return;
            }
            foreach (KeyValuePair> kv in this._timeID)
            {
                long k = kv.Key;
                if (k > timeNow)
                {
                    _minTime = k;
                    break;
                }
                this._timeOutTime.Enqueue(k);
            }
            
            // 2.找出失效时间对应的ID
            while (this._timeOutTime.Count > 0)
            {
                long time = this._timeOutTime.Dequeue();
                // 3.取出对应的TimerEntity执行逻辑
                for (int i = 0; i < this._timeID[time].Count; i++)
                {
                    TimerEntity timerEntity = this.GetChild(_timeID[time][i]);
                    if (timerEntity != null)
                    {
                        Run(timerEntity, time);
                    }
                }
                // foreach (long timerId in this._timeID[time])
                // {
                //     TimerEntity timerEntity = this.GetChild(timerId);
                //     if (timerEntity != null)
                //     {
                //         Run(timerEntity, time);
                //     }
                // }
                this._timeID.Remove(time);
            }
        
        }
        private void Run(TimerEntity timerEntity, long timestamp)
        {
            switch (timerEntity.timerType)
            {
                case TimerType.Wait:
                {
                    CTask tcs = timerEntity.callback1 as CTask;
                    this.Remove(timerEntity.ID);
                    tcs.SetResult(true);
                    break;
                }
                case TimerType.Count:
                {
                    if (timerEntity.count <= 1)
                    {
                        Action action = timerEntity.callback1 as Action;
                        this.Remove(timerEntity.ID);
                        action?.Invoke();
                        break;
                    }
                    else
                    {
                        long currTime = TimeHelper.ServerNow();
                        long tillTime = currTime - currTime % timestamp + timerEntity.time;
                        this.AddTimer(tillTime, timerEntity);
                        Action action = timerEntity.callback2 as Action;
                        action?.Invoke();
                        timerEntity.count--;
                        break;
                    }
                }
            }
        }
        private void AddTimer(long untillTime, TimerEntity timerEntity)
        {
            this._timeID.Add(untillTime, timerEntity.ID);
            if (untillTime < this._minTime)
            {
                this._minTime = untillTime;
            }
        }
        /// 
        /// 等待1帧(因为实在下一次Update里面刷新,所以WaitAsync传的值小于一帧的间隔就可以)
        /// 
        /// 
        public async CTask WaitFrameAsync()
        {
            return await WaitAsync(1);
        }
        /// 
        /// 等待time毫秒
        /// 
        /// 毫秒
        /// 
        public async CTask WaitAsync(long time)
        {
            if (time == 0)
            {
                return true;
            }
            long tillTime = TimeHelper.ServerNow() + time;
            CTask tcs = CTask.Create(false);
            TimerEntity timerEntity = this.AddChild(TimerType.Wait, 0, tcs, 1, null, true);
            this.AddTimer(tillTime, timerEntity);
            return await tcs;
        }
        /// 
        /// 等待到指定毫秒的时间戳
        /// 
        /// 毫秒
        /// 
        public async CTask WaitTillAsync(long untillTime)
        {
            if (TimeHelper.ServerNow() >= untillTime)
            {
                return true;
            }
            CTask tcs = CTask.Create();
            TimerEntity timerEntity = this.AddChild(TimerType.Wait, 0, tcs, 1, null, true);
            this.AddTimer(untillTime, timerEntity);
            return await tcs;
        }
        /// 
        /// 
        /// 
        /// 计时器Hit一次的时间(毫秒)
        /// 全部count完成时候回调
        /// 次数
        /// 针对多次执行的Timer,每一次Hit时候的回调
        /// ID, 可以通过Remove来手动中止Timer
        public TimerEntity AddTimer(long time, Action action1, int count = 1, Action action2 = null)
        {
            TimerEntity timerEntity = this.AddChild(TimerType.Count, time, action1, count, action2, true);
            this.AddTimer(TimeHelper.ServerNow() + time, timerEntity);
            return timerEntity;
        }
        public void Remove(ref long id)
        {
            this.Remove(id);
            id = 0;
        }
        public bool Remove(TimerEntity timerEntity)
        {
            if (timerEntity == null)
            {
                return false;
            }
            timerEntity.Dispose();
            return true;
        }
        public bool Remove(long id)
        {
            if (id == 0)
            {
                return false;
            }
            TimerEntity timerEntity = this.GetChild(id);
            return Remove(timerEntity);
        }
    }
}