namespace Guru
{
    using System;
    using Object = UnityEngine.Object;
    using UnityEngine;
    using System.Collections.Generic;

    
    public class GuruResManager : IResManager, IUpdater
    {
        public const string InstanceName = "guru_res_manager";
        public static float CheckRequestInterval = 3; // 检查加载队列的频率
        
        public string Name => "guru_res";
        
        private bool _isReady;
        public bool IsReady => _isReady;
        
        public Context Context { get; set; }
        
        private LoaderPool _loaderPool;

        private Queue<ResRequest> _requests;

        /// <summary>
        /// 注册资源管理器
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static GuruResManager Create(Context context)
        {
            var mgr = new GuruResManager();
            mgr.Init();
            context.RegisterResManager(mgr, InstanceName);
            return mgr;
        }

        public void Init()
        {
            _isReady = true;
            _loaderPool = LoaderPool.CreatePool();
            _requests = new Queue<ResRequest>(20);
        }
        
        public T CloneObject<T>(GameObject prefab, Transform container = null) where T :Component
        {
            var go = GameObject.Instantiate<GameObject>(prefab, container);
            if (go != null)
            {
                go.name = nameof(T).ToLower();
                return go.GetComponent<T>();
            }
            return null;
        }

        /// <summary>
        /// 加载本地资源
        /// </summary>
        /// <param name="resUri"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Load<T>(string resUri) where T : Object
        {
            return Resources.Load<T>(resUri);
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <param name="resUri"></param>
        /// <param name="onLoadComplete"></param>
        /// <typeparam name="T"></typeparam>
        public void LoadAsync(string resUri, Action<ResLoadInfo> onLoadComplete)
        {
            ResRequest req =  ResRequest.Create(resUri, onLoadComplete);
            _requests.Enqueue(req); // 添加任务
        }



        #region 帧更新

        /// <summary>
        /// 帧更新
        /// </summary>
        public void OnUpdate()
        {
            CheckLoadingList();
        }

        public bool IsStopped { get; set; } = false;

        #endregion



        #region 加载队列

        private float _checkLoadingDuration = 0;
        /// <summary>
        /// 检查加载队列
        /// </summary>
        private void CheckLoadingList()
        {
            if (_requests.Count > 0 && _loaderPool.FreeCount > 0)
            {
                _checkLoadingDuration = 0;
            }

            // 更新检查队列
            if (_checkLoadingDuration > 0)
            {
                _checkLoadingDuration -= Time.deltaTime;
                return;
            }

            // 检查队列
            while (_requests.Count > 0 && _loaderPool.FreeCount > 0)
            {
                var loader  = _loaderPool.Get();
                if (loader != null)
                {
                    var req = _requests.Dequeue();
                    loader.LoadAsync(req.resUri, req.callback);       
                }
            }
            _checkLoadingDuration = CheckRequestInterval;
        }
        

        #endregion
        
        
    }

    /// <summary>
    /// 加载器池
    /// 默认同时持有 3 个加载器
    /// </summary>
    internal class LoaderPool: IPool<ResLoaderBase>
    {
        public string Name => "loader_pool";
        public int PreSpawnCount { get; set; } = 3;
        private Queue<ResLoaderBase> _freeLoaders;

        
        public static LoaderPool CreatePool(int initCount = 3)
        {
            if (initCount < 2) initCount = 2; // 最小 2 个
            var pool = new LoaderPool(initCount);
            return pool;
        }
        
        public LoaderPool(int initCount = 0)
        {
            if (initCount > 0) PreSpawnCount = initCount;
            _freeLoaders = new Queue<ResLoaderBase>();
            if (PreSpawnCount > 0)
            {
                for (int i = 0; i < PreSpawnCount; i++)
                {
                    _freeLoaders.Enqueue(Create());
                }
            }
        }

        public ResLoaderBase Get()
        {
            if(FreeCount > 0)
            {
                return _freeLoaders.Dequeue();
            }
            return null;
        }

        public ResLoaderBase Create()
        {
            var loader = new ResLoaderBase();
            loader.OnLoaderFree = Recycle;
            return loader;
        }

        public void Recycle(ResLoaderBase obj)
        {
            _freeLoaders.Enqueue(obj);
        }
        
        public int FreeCount => _freeLoaders.Count;
    }

    /// <summary>
    /// 加载需求
    /// </summary>
    internal struct ResRequest
    {
        public string url;
        public string resUri;
        public Action<ResLoadInfo> callback; 
        
        public static ResRequest Create(string resUri, Action<ResLoadInfo> callback)
        {
            ResUriHelper.UriToType(resUri, out var type, out var url);
            return new ResRequest()
            {
                url = url,
                resUri = resUri,
                callback = callback
            };
        }
    }


}