using System;
using System.Linq;
using System.Threading.Tasks;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Runtime.Caching;
using Mapster;

namespace YGNT.Infrastructure.AbpEntity
{
    public class MyCacheBase<TEntity, TCacheItem, TPrimaryKey> : ICacheBase<TCacheItem, TPrimaryKey>
        where TEntity : class, IEntity<TPrimaryKey> where TCacheItem : class
    {
        protected readonly ICacheManager CacheManager;
        protected TimeSpan ExpireTime;
        protected string CacheName;
        protected readonly IRepository<TEntity, TPrimaryKey> Repository;

        public MyCacheBase(IRepository<TEntity, TPrimaryKey> repository, ICacheManager cacheManager, string cacheName = null, TimeSpan? expireTime = null)
        {
            Repository = repository;
            CacheName = cacheName ?? GetDefaultCacheName();
            CacheManager = cacheManager;
            if (expireTime == null)
                ExpireTime = TimeSpan.FromMinutes(60);
            else
                ExpireTime = (TimeSpan)expireTime;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <returns></returns>
        public async Task<TCacheItem> GetCacheItemAsync(TPrimaryKey id)
        {
            var cache = CacheManager.GetCache<TPrimaryKey, TCacheItem>(CacheName);
            var cacheItem = await cache.GetOrDefaultAsync(id);
            if (cacheItem == null)
            {
                cacheItem = await GetCacheItemFromDbAsync(id);
                await cache.SetAsync(id, cacheItem, ExpireTime);
            }
            return cacheItem;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <returns></returns>
        public TCacheItem GetCacheItem(TPrimaryKey id)
        {
            var cache = CacheManager.GetCache<TPrimaryKey, TCacheItem>(CacheName);
            var cacheItem = cache.GetOrDefault(id);
            if (cacheItem == null)
            {
                cacheItem = GetCacheItemFromDb(id);
                cache.SetAsync(id, cacheItem, ExpireTime);
            }
            return cacheItem;
        }

        protected virtual async Task<TCacheItem> GetCacheItemFromDbAsync(TPrimaryKey id)
        {
            var entity = await Repository.FirstOrDefaultAsync(id);
            var cacheItem = entity?.Adapt<TCacheItem>();
            return cacheItem;
        }
        protected virtual TCacheItem GetCacheItemFromDb(TPrimaryKey id)
        {
            var entity = Repository.FirstOrDefault(id);
            var cacheItem = entity?.Adapt<TCacheItem>();
            return cacheItem;
        }

        protected virtual string GetDefaultCacheName()
        {
            return typeof(TCacheItem).FullName;
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="id"></param>
        public void Remove(TPrimaryKey id)
        {
            var cache = CacheManager.GetCache<TPrimaryKey, TCacheItem>(CacheName);
            cache.Remove(id);
        }
    }
}