using QRRapidoApp.Models.DTOs;
using QRRapidoApp.Models.ViewModels;
using System.Security.Cryptography;
using System.Text;

namespace QRRapidoApp.Services
{
    public class QRBusinessManager : IQRBusinessManager
    {
        private readonly IQRCodeService _qrService;
        private readonly IQuotaValidator _quotaValidator;
        private readonly IUserService _userService;
        private readonly ILogger<QRBusinessManager> _logger;

        public QRBusinessManager(
            IQRCodeService qrService,
            IQuotaValidator quotaValidator,
            IUserService userService,
            ILogger<QRBusinessManager> logger)
        {
            _qrService = qrService;
            _quotaValidator = quotaValidator;
            _userService = userService;
            _logger = logger;
        }

        public async Task<QRResponseDto> ProcessGenerationAsync(QRGenerationRequest request, UserRequesterContext context)
        {
            var quotaCheck = await _quotaValidator.ValidateQuotaAsync(context);
            if (!quotaCheck.CanProceed)
            {
                return new QRResponseDto { Success = false, ErrorCode = quotaCheck.ErrorCode, Message = quotaCheck.ErrorMessage };
            }

            // Garantir que campos básicos não sejam nulos para o Hash
            string content = request.Content ?? "";
            string type = request.Type ?? "url";
            string corner = request.CornerStyle ?? "square";
            string primary = request.PrimaryColor ?? "#000000";
            string bg = request.BackgroundColor ?? "#FFFFFF";

            var contentHash = ComputeSha256Hash(content + type + corner + primary + bg);

            if (context.IsAuthenticated)
            {
                var duplicate = await _userService.FindDuplicateQRAsync(context.UserId!, contentHash);
                if (duplicate != null)
                {
                    var user = await _userService.GetUserAsync(context.UserId!);
                    return new QRResponseDto
                    {
                        Success = true,
                        QRCodeBase64 = duplicate.QRCodeBase64,
                        QRId = duplicate.Id,
                        FromCache = true,
                        Message = "Recuperado do histórico (sem custo)",
                        RemainingCredits = user?.Credits ?? 0,
                        RemainingFreeQRs = 5 - (user?.FreeQRsUsed ?? 5)
                    };
                }
            }

            request.IsPremium = context.IsAuthenticated;
            var generationResult = await _qrService.GenerateRapidAsync(request);

            if (!generationResult.Success)
            {
                return new QRResponseDto { Success = false, Message = generationResult.ErrorMessage };
            }

            int cost = context.IsAuthenticated ? 1 : 0;
            await _userService.SaveQRToHistoryAsync(context.UserId, generationResult, cost);
            await _quotaValidator.RegisterUsageAsync(context, generationResult.QRId, cost);

            int credits = 0, freeUsed = 0;
            if (context.IsAuthenticated)
            {
                var user = await _userService.GetUserAsync(context.UserId!);
                credits = user?.Credits ?? 0;
                freeUsed = user?.FreeQRsUsed ?? 5;
            }

            return new QRResponseDto
            {
                Success = true,
                QRCodeBase64 = generationResult.QRCodeBase64,
                QRId = generationResult.QRId,
                GenerationTimeMs = generationResult.GenerationTimeMs,
                RemainingCredits = credits,
                RemainingFreeQRs = context.IsAuthenticated ? (5 - freeUsed) : 3
            };
        }

        private string ComputeSha256Hash(string rawData)
        {
            using (SHA256 sha256Hash = SHA256.Create())
            {
                byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                    builder.Append(bytes[i].ToString("x2"));
                return builder.ToString();
            }
        }
    }
}