using Microsoft.AspNetCore.Mvc; using QRRapidoApp.Models.ViewModels; using QRRapidoApp.Services; using System.Diagnostics; using System.Security.Claims; using System.Text; namespace QRRapidoApp.Controllers { [ApiController] [Route("api/[controller]")] public class QRController : ControllerBase { private readonly IQRCodeService _qrService; private readonly IUserService _userService; private readonly AdDisplayService _adService; private readonly ILogger _logger; public QRController(IQRCodeService qrService, IUserService userService, AdDisplayService adService, ILogger logger) { _qrService = qrService; _userService = userService; _adService = adService; _logger = logger; } [HttpPost("GenerateRapid")] public async Task GenerateRapid([FromBody] QRGenerationRequest request) { var stopwatch = Stopwatch.StartNew(); try { // Quick validations if (string.IsNullOrWhiteSpace(request.Content)) { return BadRequest(new { error = "Conteúdo é obrigatório", success = false }); } if (request.Content.Length > 4000) // Limit to maintain speed { return BadRequest(new { error = "Conteúdo muito longo. Máximo 4000 caracteres.", success = false }); } // Check user status var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; var user = await _userService.GetUserAsync(userId); // Rate limiting for free users if (!await CheckRateLimitAsync(userId, user)) { return StatusCode(429, new { error = "Limite de QR codes atingido", upgradeUrl = "/Premium/Upgrade", success = false }); } // Configure optimizations based on user request.IsPremium = user?.IsPremium == true; request.OptimizeForSpeed = true; // Generate QR code var result = await _qrService.GenerateRapidAsync(request); if (!result.Success) { return StatusCode(500, new { error = result.ErrorMessage, success = false }); } // Update counter for free users if (!request.IsPremium && userId != null) { var remaining = await _userService.DecrementDailyQRCountAsync(userId); result.RemainingQRs = remaining; } // Save to history if user is logged in (fire and forget) if (userId != null) { _ = Task.Run(async () => { try { await _userService.SaveQRToHistoryAsync(userId, result); } catch (Exception ex) { _logger.LogError(ex, "Error saving QR to history"); } }); } stopwatch.Stop(); // Performance logging _logger.LogInformation($"QR Rapido generated in {stopwatch.ElapsedMilliseconds}ms " + $"(service: {result.GenerationTimeMs}ms, " + $"cache: {result.FromCache}, " + $"user: {(request.IsPremium ? "premium" : "free")})"); return Ok(result); } catch (Exception ex) { _logger.LogError(ex, "Error in rapid QR code generation"); return StatusCode(500, new { error = "Erro interno do servidor", success = false }); } } [HttpGet("Download/{qrId}")] public async Task Download(string qrId, string format = "png") { try { var qrData = await _userService.GetQRDataAsync(qrId); if (qrData == null) { return NotFound(); } var contentType = format.ToLower() switch { "svg" => "image/svg+xml", "pdf" => "application/pdf", _ => "image/png" }; var fileName = $"qrrapido-{DateTime.Now:yyyyMMdd-HHmmss}.{format}"; if (format.ToLower() == "svg") { var svgContent = await _qrService.ConvertToSvgAsync(qrData.QRCodeBase64); return File(svgContent, contentType, fileName); } else if (format.ToLower() == "pdf") { var pdfContent = await _qrService.ConvertToPdfAsync(qrData.QRCodeBase64, qrData.Size); return File(pdfContent, contentType, fileName); } var imageBytes = Convert.FromBase64String(qrData.QRCodeBase64); return File(imageBytes, contentType, fileName); } catch (Exception ex) { _logger.LogError(ex, $"Error downloading QR {qrId}"); return StatusCode(500); } } [HttpPost("SaveToHistory")] public async Task SaveToHistory([FromBody] SaveToHistoryRequest request) { try { var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return Unauthorized(); } var qrData = await _userService.GetQRDataAsync(request.QrId); if (qrData == null) { return NotFound(); } // QR is already saved when generated, just return success return Ok(new { success = true, message = "QR Code salvo no histórico!" }); } catch (Exception ex) { _logger.LogError(ex, "Error saving QR to history"); return StatusCode(500, new { error = "Erro ao salvar no histórico." }); } } [HttpGet("History")] public async Task GetHistory(int limit = 20) { try { var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return Unauthorized(); } var history = await _userService.GetUserQRHistoryAsync(userId, limit); return Ok(history); } catch (Exception ex) { _logger.LogError(ex, "Error getting QR history"); return StatusCode(500); } } private async Task CheckRateLimitAsync(string? userId, Models.User? user) { if (user?.IsPremium == true) return true; var dailyLimit = userId != null ? 50 : 10; // Logged in: 50/day, Anonymous: 10/day var currentCount = await _userService.GetDailyQRCountAsync(userId); return currentCount < dailyLimit; } } public class SaveToHistoryRequest { public string QrId { get; set; } = string.Empty; } }