using System;

using BirdsiteLive.Twitter.Models;

using Microsoft.Extensions.Caching.Memory;

namespace BirdsiteLive.Twitter
{
    public interface ICachedTwitterTweetsService : ITwitterTweetsService
    {
        void PurgeTweet(long statusId);
    }

    public class CachedTwitterTweetsService : ICachedTwitterTweetsService
    {
        private readonly ITwitterTweetsService _twitterService;

        private MemoryCache _tweetCache = new MemoryCache(
            new MemoryCacheOptions() { SizeLimit = 5000 }
        );
        private MemoryCacheEntryOptions _cacheEntryOptions = new MemoryCacheEntryOptions()
            .SetSize(1) //Size amount
            //Priority on removing when reaching size limit (memory pressure)
            .SetPriority(CacheItemPriority.High)
            // Keep in cache for this time, reset time if accessed.
            // We set this lower than a user's in case they delete this Tweet for some reason; we don't need that cached.
            .SetSlidingExpiration(TimeSpan.FromHours(2))
            // Remove from cache after this time, regardless of sliding expiration
            .SetAbsoluteExpiration(TimeSpan.FromDays(7));

        #region Ctor
        public CachedTwitterTweetsService(ITwitterTweetsService twitterService)
        {
            _twitterService = twitterService;
        }

        public ExtractedTweet[] GetTimeline(string username, int nberTweets, long fromTweetId = -1)
        {
            // This sounds like it'd be silly to cache; pass this directly to TwitterService.
            // Theoretically this shouldn't be called more than once every 15 min anyway?
            return _twitterService.GetTimeline(username, nberTweets, fromTweetId);
        }

        public ExtractedTweet GetTweet(long statusId)
        {
            if (!_tweetCache.TryGetValue(statusId, out ExtractedTweet tweet))
            {
                tweet = _twitterService.GetTweet(statusId);

                // Unlike with the user cache, save the null value anyway to prevent (quicker) API exhaustion.
                // It's incredibly unlikely that a tweet with this ID is going to magickally appear within 2 hours.
                _tweetCache.Set(statusId, tweet, _cacheEntryOptions);
            }

            return tweet;
        }
        #endregion

        public void PurgeTweet(long statusId)
        {
            _tweetCache.Remove(statusId);
        }
    }
}
