using Microsoft.Extensions.Caching.Memory;
using OnlyOneAccessTemplate.Models.RateLimits;

namespace OnlyOneAccessTemplate.Services
{
    public class RateLimitService : IRateLimitService
    {
        private readonly IMemoryCache _cache;
        private readonly IConfiguration _configuration;
        private const int MAX_REQUESTS_PER_HOUR = 50;
        private const int CAPTCHA_THRESHOLD = 20;

        public RateLimitService(IMemoryCache cache, IConfiguration configuration)
        {
            _cache = cache;
            _configuration = configuration;
        }

        public async Task<bool> ShouldShowCaptchaAsync(string ipAddress)
        {
            var key = $"rate_limit_{ipAddress}";
            if (_cache.TryGetValue(key, out RateLimitEntry entry))
            {
                // Resetar contador se passou mais de 1 hora
                if (DateTime.UtcNow.Subtract(entry.LastRequest).TotalHours > 1)
                {
                    entry.RequestCount = 0;
                }

                return entry.RequestCount >= CAPTCHA_THRESHOLD;
            }
            return false;
        }

        public async Task RecordRequestAsync(string ipAddress)
        {
            var key = $"rate_limit_{ipAddress}";
            if (_cache.TryGetValue(key, out RateLimitEntry entry))
            {
                entry.RequestCount++;
                entry.LastRequest = DateTime.UtcNow;
            }
            else
            {
                entry = new RateLimitEntry
                {
                    IpAddress = ipAddress,
                    RequestCount = 1,
                    LastRequest = DateTime.UtcNow
                };
            }

            _cache.Set(key, entry, TimeSpan.FromHours(2));
        }

        public async Task<(bool IsValid, string Challenge)> GenerateCaptchaAsync()
        {
            // Captcha matemático simples
            var random = new Random();
            var num1 = random.Next(1, 10);
            var num2 = random.Next(1, 10);
            var operation = random.Next(0, 2) == 0 ? "+" : "-";

            var challenge = $"{num1} {operation} {num2}";
            var answer = operation == "+" ? num1 + num2 : num1 - num2;

            var challengeKey = Guid.NewGuid().ToString();
            _cache.Set($"captcha_{challengeKey}", answer, TimeSpan.FromMinutes(10));

            return (true, $"{challenge}|{challengeKey}");
        }

        public async Task<bool> ValidateCaptchaAsync(string challenge, string response)
        {
            if (string.IsNullOrEmpty(challenge) || string.IsNullOrEmpty(response))
                return false;

            var parts = challenge.Split('|');
            if (parts.Length != 2) return false;

            var challengeKey = parts[1];
            var cacheKey = $"captcha_{challengeKey}";

            if (_cache.TryGetValue(cacheKey, out int expectedAnswer))
            {
                _cache.Remove(cacheKey);
                if (int.TryParse(response, out int userAnswer))
                {
                    return userAnswer == expectedAnswer;
                }
            }

            return false;
        }
    }
}
