using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MrWu.Debug;

namespace Server.Core
{
    public class CoroutineLockManager : ICoroutineLockManager
    {
        /// <summary>
        /// 协程锁类型队列
        /// </summary>
        private readonly Dictionary<int, CoroutineLockQueueType> CoroutineLockQueueTypes =
            new Dictionary<int, CoroutineLockQueueType>();

        /// <summary>
        /// item1 协程锁类型 item2 锁的key item3 锁的层级
        /// </summary>
        private readonly Queue<(int, long, int)> nextFrameRun = new Queue<(int, long, int)>();
        
        private CoroutineLockQueueType GetOrAdd(int coroutineLockType)
        {
            if (!this.CoroutineLockQueueTypes.TryGetValue(coroutineLockType,
                    out CoroutineLockQueueType coroutineLockQueueType))
            {
                coroutineLockQueueType = new CoroutineLockQueueType(coroutineLockType,this);
                this.CoroutineLockQueueTypes.Add(coroutineLockType, coroutineLockQueueType);
            }

            return coroutineLockQueueType;
        }

        private CoroutineLockQueueType Get(int coroutineLockType)
        {
            if (!this.CoroutineLockQueueTypes.TryGetValue(coroutineLockType,
                    out CoroutineLockQueueType coroutineLockQueueType))
            {
                coroutineLockQueueType = null;
            }
            return coroutineLockQueueType;
        }

        public void Update()
        {
            while (this.nextFrameRun.Count > 0)
            {
                Debug.Log("Update!");
                (int coroutineLockType, long key, int count) = this.nextFrameRun.Dequeue();
                this.Notify(coroutineLockType, key, count);
            }
        }

        public void RunNextCoroutine(int coroutineLockType,long key,int level)
        {
            if (level == 100)
            {
                Debug.Warning($"too much coroutine level: {coroutineLockType} {key}");
            }
            
            Debug.Log("RunNextCoroutine !!!");
            this.nextFrameRun.Enqueue((coroutineLockType,key,level));
        }
        
        private void Notify(int coroutineLockType, long key, int level)
        {
            Debug.Log($"Notify {coroutineLockType} {key} {level}");
            CoroutineLockQueueType coroutineLockQueueType = Get(coroutineLockType);
            if (coroutineLockQueueType == null)
            {
                Debug.Error("coroutineLockQueueType is null!");
                return;
            }

            coroutineLockQueueType.Notify(key, level);
        }

        #region ICoroutineLockManager
        
        /// <summary>
        /// 获取协程锁
        /// </summary>
        /// <param name="coroutineLockType"></param>
        /// <param name="key"></param>
        /// <param name="time"></param>
        public async Task<CoroutineLock> Wait(int coroutineLockType, long key, int time = 600000)
        {
            CoroutineLockQueueType coroutineLockQueueType = this.GetOrAdd(coroutineLockType);
            //Debug.Log("CoroutineLockManager Wait");
            return await coroutineLockQueueType.Wait(key, time);
        }
        
        #endregion
    }
}