using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TFramework
{
    public class EditorReferencePool
    {
        private static Dictionary<Type, List<IReference>> _referencePools = new Dictionary<Type, List<IReference>>();

        /// <summary>
        /// 获取引用数量
        /// </summary>
        /// <param name="type">引用类型</param>
        /// <returns>引用数量</returns>
        public static int GetRerenceCount(Type type)
        {
            if (_referencePools.ContainsKey(type))
                return _referencePools[type].Count;
            else
                throw new UnityException($"获取引用数量失败，不存在引用池{type.FullName}！");
        }

        /// <summary>
        /// 生成引用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Spawn<T>() where T : class, IReference, new()
        {
            Type type = typeof(T);
            RegisterRefer(type);
            T obj = null;
            if (GetRerenceCount(type) > 0)
            {
                obj = _referencePools[type][0] as T;
                _referencePools[type].Remove(obj);
            }
            else
                obj = new T();
            return obj;
        }

        /// <summary>
        /// 生成指定条件引用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T Spawn<T>(Predicate<T> predicate) where T : class, IReference, new()
        {
            Type type = typeof(T);
            RegisterRefer(type);
            T obj = null;
            if (GetRerenceCount(type) > 0)
            {
                IReference reference = _referencePools[type].Find(p=>(bool)predicate?.Invoke(p as T));
                if(reference!=null)
                {
                    obj = reference as T;
                    _referencePools[type].Remove(reference);
                }
                else
                    obj = new T();
            }
            else
                obj = new T();
            return obj;
        }

        /// <summary>
        /// 回收引用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void Recycle<T>(T refer) where T : class, IReference, new()
        {
            Type type = refer.GetType();
            RegisterRefer(type);
            _referencePools[type].Add(refer);
        }

        /// <summary>
        /// 批量回收引用
        /// </summary>
        /// <typeparam name="T">引用类型</typeparam>
        /// <param name="refes">引用集合</param>
        public static void Recycles<T>(List<T> refes) where T : class, IReference, new() => Recycles<T>(refes.ToArray());

        /// <summary>
        /// 批量回收引用
        /// </summary>
        /// <typeparam name="T">引用类型</typeparam>
        /// <param name="refes">引用数组</param>
        public static void Recycles<T>(T[] refes) where T : class, IReference, new()
        {
            if (refes == null) return;
            Type type = typeof(T);
            RegisterRefer(type);
            for (int i = 0; i < refes.Length; i++)
                _referencePools[type].Add(refes[i]);
        }

        /// <summary>
        /// 清空指定引用池
        /// </summary>
        /// <param name="type">引用类型</param>
        public static void Clear(Type type) => _referencePools[type].Clear();

        /// <summary>
        /// 清空所有引用池
        /// </summary>
        public static void ClearAll()
        {
            foreach (var refer in _referencePools)
                refer.Value.Clear();
        }

        /// <summary>
        /// 注册引用
        /// </summary>
        /// <param name="type">引用类型</param>
        private static void RegisterRefer(Type type)
        {
            if (!_referencePools.ContainsKey(type))
                _referencePools.Add(type, new List<IReference>());
        }
    }
}
