using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Server.Core
{
    public static partial class ReferencePool
    {
        private static ConcurrentDictionary<Type, Pool> objPool = new ConcurrentDictionary<Type, Pool>();

        private static readonly Func<Type, Pool> AddPoolFunc = type => new Pool(type, 100);

        public static T Fetch<T>(bool isFromPool = true) where T : IReference
        {
            return (T)Fetch(typeof(T),isFromPool);
        }

        private static long refreshId = long.MinValue;

        public static long GetRefreshId()
        {
            return Interlocked.Increment(ref refreshId);
        }

        public static object Fetch(Type type, bool isFromPool = true)
        {
            if (!isFromPool)
            {
                return Activator.CreateInstance(type);
            }
            
            //Debug.Log($"ReferencePool Fetch {type}");
            
            Pool pool = GetPool(type);
            object obj = pool.Get();

            if (obj is IReference p)
            {
                p.IsFromPool = true;
                p.ReferenceId = GetRefreshId();
            }

            return obj;
        }

        public static void Recycle(IReference p)
        {
            if (!p.IsFromPool)
            {
                return;
            }

            // 防止多次入池
            p.IsFromPool = false;
            //p.Dispose();

            Type type = p.GetType();
            //Debug.Log($"ReferencePool Recycle {type}");
            Pool pool = GetPool(type);
            pool.Return(p);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Pool GetPool(Type type)
        {
            return objPool.GetOrAdd(type, AddPoolFunc);
        }

        /// <summary>
        /// 获取对象池中的所有对象
        /// </summary>
        /// <returns></returns>
        public static Type[] GetPoolTypes()
        {
            return objPool.Keys.ToArray();
        }

        public static int GetPoolCnt(Type type)
        {
            Pool pool = GetPool(type);
            if (pool != null)
            {
                return pool.NumItems;
            }

            return 0;
        }
    }
}