using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace AsbCloudInfrastructure.Services.Cache
{
    public class CacheDb
    {
        private readonly ConcurrentDictionary<string, CacheTableDataStore> cache =
            new ConcurrentDictionary<string, CacheTableDataStore>();

        public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, params string[] includes)
            where TEntity : class
            => GetCachedTable<TEntity>(context, new SortedSet<string>(includes));

        public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, ISet<string> includes = null)
            where TEntity : class
        {
            var cacheItem = GetCacheTableDataStore<TEntity>();
            var tableCache = new CacheTable<TEntity>(context, cacheItem, includes);
            return tableCache;
        }

        public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> configureDbSet)
            where TEntity : class
        {
            var cacheItem = GetCacheTableDataStore<TEntity>();
            var tableCache = new CacheTable<TEntity>(context, cacheItem, configureDbSet);
            return tableCache;
        }

        private CacheTableDataStore GetCacheTableDataStore<TEntity>()
            where TEntity : class
        {
            var nameOfTEntity = typeof(TEntity).FullName;
            var cacheItem = cache.GetOrAdd(nameOfTEntity, (nameOfTEntity) => new CacheTableDataStore
            {
                NameOfTEntity = nameOfTEntity,
                Entities = new List<TEntity>(),
            });
            return cacheItem;
        }

        public void DropAll() => cache.Clear();

        public void Drop<TEntity>() => cache.Remove(typeof(TEntity).FullName, out _);
    }
}