using Microsoft.AspNetCore.Http;
using System.Xml;

namespace Kit.Helpers.Repository.Xml
{
    public abstract class EntityXmlPersistentSimpleRepositoryWithCache<TEntity, TKey, TFilter, TContextKey> : EntityXmlPersistentSimpleRepository<TEntity, TKey, TFilter, TContextKey>
        where TEntity : XmlSimpleClass<TKey, TContextKey>
        where TFilter : IXmlSimpleFilter<TContextKey, TKey>
    {
        private string _cacheKey;
        protected bool _cacheOn;

        private void CacheInit()
        {
            _cacheKey = this.GetType().FullName;
            _cacheOn = true;
        }

        public EntityXmlPersistentSimpleRepositoryWithCache(string elementName)
            : base(elementName)
        {
            this.CacheInit();
        }

        public EntityXmlPersistentSimpleRepositoryWithCache(string path, string elementName) : base(path, elementName)
        {
            this.CacheInit();
        }
        //public EntityXmlPersistentSimpleRepository2(string elementName, TContext data, IConverter<XmlNode, TEntity> converter)
        //    : base(elementName, data, converter)
        //{
        //}
        //public EntityXmlPersistentSimpleRepository2(string rootElementName, string path, string elementName, TContext data);
        //public EntityXmlPersistentSimpleRepository2(string path, string elementName, TContext data, IConverter<XmlNode, TEntity> converter);
        //public EntityXmlPersistentSimpleRepository2(string rootElementName, string path, string elementName, TContext data, IConverter<XmlNode, TEntity> converter);
        //public EntityXmlPersistentSimpleRepository2(string elementsAfterPostion, string rootElementName, string path, string elementName, TContext data, IConverter<XmlNode, TEntity> converter);

        private Dictionary<string, TEntity>? GetCacheDictionary(ISelectContext selectContext)
        {
            HttpContext? httpContext = HttpContextCore.Current;
            if (httpContext == null && selectContext == null)
            {
                return null;
            }

            IDictionary<object, object?>? items = selectContext != null ? selectContext.Items : httpContext!.Items;

            lock (items)
            {
                Dictionary<string, TEntity> cacheDictionary = (Dictionary<string, TEntity>)items[_cacheKey];

                if (cacheDictionary == null)
                {
                    cacheDictionary = new Dictionary<string, TEntity>();
                    items[_cacheKey] = cacheDictionary;
                }

                return cacheDictionary;
            }
        }

        private TEntity GetFromCache(string key, Func<TEntity> getAction, ISelectContext selectContext = null)
        {
            TEntity entity = null;
            if (_cacheOn)
            {
                Dictionary<string, TEntity>? cacheDictionary = this.GetCacheDictionary(selectContext);
                if (cacheDictionary != null)
                {
                    lock (cacheDictionary)
                    {
                        entity = cacheDictionary.GetByKey(key);
                        if (entity == null)
                        {
                            entity = getAction();
                            cacheDictionary.SetByKey(key, entity);
                        }
                    }
                }
            }

            return entity ?? getAction();
        }

        public override TEntity Get(XmlDocument db, TKey key)
        {
            string projectGuid = db.DocumentElement.GetValueAttribute("guid", string.Empty);
            string cacheKey = "{0}_{1}".ApplyFormat(projectGuid, key);

            return this.GetFromCache(cacheKey, () => base.Get(db, key));
        }

        public override TEntity Get(XmlDocument db, TKey key, TFilter filter)
        {
            string projectGuid = db.DocumentElement.GetValueAttribute("guid", string.Empty);
            string cacheKey = "{0}_{1}".ApplyFormat(projectGuid, key);

            return null;// this.GetFromCache(cacheKey, () => base.Get(db, key, filter), (ISelectContext)filter.GetPropertyValue("SelectContext"));
        }
    }
}
