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 async Task<IEnumerable<TEntity>> GetCacheAsync(CancellationToken token)
    {
        var cache = await memoryCache.GetOrCreateAsync(CacheTag, async (cacheEntry) =>
        {
            cacheEntry.AbsoluteExpirationRelativeToNow = CacheObsolescence;
            cacheEntry.SlidingExpiration = CacheObsolescence;

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