using System;

namespace ExtensiblePortfolioSite.SDK.Caching
{
    /// <summary>
    /// Base Git Cache Item Class
    /// </summary>
    public abstract class GitCacheItemBase : IDisposable, ICacheItem
    {
        /// <summary>
        /// the <see cref="GitServiceCache"/> this Item is bound to
        /// </summary>
        protected readonly GitServiceCache Parent;

        /// <inheritdoc cref="GitCacheItemBase"/>
        /// <param name="Parent"><see cref="GitServiceCache"/> that this Item is boud to</param>
        public GitCacheItemBase(GitServiceCache Parent)
        {
            this.Parent = Parent;
            Parent.Register(this);
        }
        ///
        ~GitCacheItemBase() => this.Disposing();

        /// <inheritdoc cref="ICacheItem.Invalidate"/>
        public abstract void Invalidate();

        /// <inheritdoc cref="IDisposable.Dispose"/>
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            this.Disposing();
        }
        private void Disposing() => this.Parent.Unregister(this);

    }

    /// <summary>
    /// Base Git Cache Item Class
    /// </summary>
    /// <typeparam name="T">Cache </typeparam>
    public abstract class GitCacheItemBase<T> : GitCacheItemBase, ICacheItem<T>
    {
        private T CacheValue;
        private DateTime RetrivedTime;

        internal GitCacheItemBase(GitServiceCache Parent) : base(Parent)
        {
            this.RetrivedTime = DateTime.MinValue;
            this.CacheValue = default!;
        }

        /// <inheritdoc cref="GitCacheItemBase.Invalidate"/>
        public override void Invalidate()
        {
            this.CacheValue = default!;
            this.RetrivedTime = DateTime.MinValue;
        }
        /// <inheritdoc cref="ICacheItem{T}.GetValue"/>
        public T GetValue()
        {
            if (DateTime.Now - this.RetrivedTime > this.Lifetime)
            {
                this.CacheValue = RetriveValue();
                this.RetrivedTime = DateTime.Now;
            }
            return this.CacheValue!;
        }

        /// <summary>
        /// Get Expected Cache Item Lifetime
        /// </summary>
        protected abstract TimeSpan Lifetime { get; }
        /// <summary>
        /// Retrive the Cache Item
        /// </summary>
        /// <returns>Cache Item</returns>
        protected abstract T RetriveValue();
    }
}
