using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Repository
{

    public class CacheBase<TEntity> : QueryContainer<TEntity>
        where TEntity : class, AsbCloudDb.Model.IId
    {
        protected readonly IMemoryCache memoryCache;
        protected string CacheTag = typeof(TEntity).Name;
        protected TimeSpan CacheObsolescence = TimeSpan.FromMinutes(5);

        public CacheBase(IAsbCloudDbContext context, IMemoryCache memoryCache) 
            : base(context)
        {
            this.memoryCache = memoryCache;
        }

        public CacheBase(IAsbCloudDbContext context, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery) 
            : base(context, makeQuery)
        {
            this.memoryCache = memoryCache;
        }

        protected virtual void DropCache()
            => memoryCache.Remove(CacheTag);

        protected virtual IEnumerable<TEntity> GetCache()
        {
            var cache = memoryCache.GetOrCreate(CacheTag, cacheEntry =>
            {
                cacheEntry.AbsoluteExpirationRelativeToNow = CacheObsolescence;
                cacheEntry.SlidingExpiration = CacheObsolescence;

                var entities = this.GetQuery().ToArray();
                cacheEntry.Value = entities;
                return entities;
            });
            return cache;
        }

        protected virtual Task<IEnumerable<TEntity>> GetCacheAsync(CancellationToken token)
        {
            var cache = memoryCache.GetOrCreateAsync(CacheTag, async (cacheEntry) =>
            {
                cacheEntry.AbsoluteExpirationRelativeToNow = CacheObsolescence;
                cacheEntry.SlidingExpiration = CacheObsolescence;

                var entities = await this.GetQuery().ToArrayAsync(token);
                cacheEntry.Value = entities;
                return entities.AsEnumerable();
            });
            return cache;
        }
    }

}