using System.Data;

namespace Fast.Logic;

public class LockoutCache
{
    private static Dictionary<int, bool> UserLockoutCache = new();
    private static DateTime LastCacheRefresh = DateTime.MinValue;
    private static readonly SemaphoreSlim CacheRefreshSemaphore = new(1, 1);
    private static TimeSpan RefreshInterval { get; set; }

    public LockoutCache(TimeSpan refreshInterval)
    {
        RefreshInterval = refreshInterval;
    }

    public async Task<bool> IsUserLockedOut(int UserId)
    {
        if (DateTime.UtcNow - LastCacheRefresh > RefreshInterval)
            await RefreshLockoutCacheAsync();

        while (LastCacheRefresh == DateTime.MinValue)
            await Task.Delay(100);

        bool isLockedOut = true;

        //if the user is not in the cache, assume they are locked out
        isLockedOut = UserLockoutCache.GetValueOrDefault(UserId, true);

        return isLockedOut;
    }

    private static async Task RefreshLockoutCacheAsync()
    {
        if (await CacheRefreshSemaphore.WaitAsync(0))
        {
            try
            {
                using var db = Main.CreateContext();
                var lockoutValsOriginal = await db.AppUsers.Select(x => new { x.Id, x.LockoutEnd }).ToListAsync();
                var newUserLockoutCache = lockoutValsOriginal.ToDictionary(x => x.Id, x => x.LockoutEnd.HasValue && x.LockoutEnd.Value.ToUniversalTime() > DateTimeOffset.UtcNow);
                UserLockoutCache = newUserLockoutCache;
            }
            finally
            {
                LastCacheRefresh = DateTime.UtcNow;
                CacheRefreshSemaphore.Release();
            }
        }
    }
}
