using System.Collections.Concurrent;
using AyCode.Core.Extensions;
using AyCode.Utils.Extensions;

namespace AyCode.Database.DataLayers
{
    public sealed class PooledDal
    {
        private static readonly PooledDal Instance = new();
        
        private readonly ConcurrentDictionary<Guid, ConcurrentDictionary<Type, IAcDalBase>> _dataLayersPoolById = new();
        private static ConcurrentDictionary<Guid, ConcurrentDictionary<Type, IAcDalBase>> DataLayersPoolById => Instance._dataLayersPoolById;

        public static int Count => DataLayersPoolById.Count;
        public static void Clear() => DataLayersPoolById.Clear();

        public static TDal CreateDal<TDal>() where TDal : IAcDalBase => Activator.CreateInstance<TDal>();

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TDal"></typeparam>
        /// <param name="id">ONLY SessionId or logged in PlayerId!</param>
        /// <returns></returns>
        public static TDal GetDalById<TDal>(Guid id) where TDal : IAcDalBase
        {
            if (id.IsNullOrEmpty()) return CreateDal<TDal>(); //TODO: A Guid.Empty id-t ÁTGONDOLNI! - J.

            if (DataLayersPoolById.TryGetValue(id, out var dataLayersByType)) 
                return GetDalByType<TDal>(dataLayersByType);

            dataLayersByType = new ConcurrentDictionary<Type, IAcDalBase>();
            DataLayersPoolById.TryAdd(id, dataLayersByType);

            return GetDalByType<TDal>(dataLayersByType);
        }

        private static TDal GetDalByType<TDal>(ConcurrentDictionary<Type, IAcDalBase> dataLayersByType) where TDal : IAcDalBase
        {
            if (dataLayersByType.TryGetValue(typeof(TDal), out var dataLayer))
                return (TDal)dataLayer;

            var resultDal = CreateDal<TDal>();
            dataLayersByType.TryAdd(typeof(TDal), resultDal);

            return resultDal;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id">SessionId or PlayerId</param>
        /// <returns></returns>
        public static bool Remove(Guid id)//, bool keepGuidEmptyId = true)
        {
            //if (keepGuidEmptyId && id == Guid.Empty) return false;

            if (!DataLayersPoolById.TryRemove(id, out var dataLayersByType))
                return false;

            dataLayersByType.Clear();
            return true;
        }
    }
}