using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using QRRapidoApp.Models.ViewModels; using QRRapidoApp.Services; using System.Security.Claims; namespace QRRapidoApp.Controllers { public class AccountController : Controller { private readonly IUserService _userService; private readonly AdDisplayService _adDisplayService; private readonly ILogger _logger; public AccountController(IUserService userService, AdDisplayService adDisplayService, ILogger logger) { _userService = userService; _adDisplayService = adDisplayService; _logger = logger; } [HttpGet] public IActionResult Login(string returnUrl = "/") { ViewBag.ReturnUrl = returnUrl; return View(); } [HttpGet] public IActionResult LoginGoogle(string returnUrl = "/") { var properties = new AuthenticationProperties { RedirectUri = Url.Action("GoogleCallback"), Items = { { "returnUrl", returnUrl } } }; return Challenge(properties, GoogleDefaults.AuthenticationScheme); } [HttpGet] public IActionResult LoginMicrosoft(string returnUrl = "/") { var properties = new AuthenticationProperties { RedirectUri = Url.Action("MicrosoftCallback"), Items = { { "returnUrl", returnUrl } } }; return Challenge(properties, MicrosoftAccountDefaults.AuthenticationScheme); } [HttpGet] public async Task GoogleCallback() { return await HandleExternalLoginCallbackAsync(GoogleDefaults.AuthenticationScheme); } [HttpGet] public async Task MicrosoftCallback() { return await HandleExternalLoginCallbackAsync(MicrosoftAccountDefaults.AuthenticationScheme); } private async Task HandleExternalLoginCallbackAsync(string scheme) { try { var result = await HttpContext.AuthenticateAsync(scheme); if (!result.Succeeded) { _logger.LogWarning($"External authentication failed for scheme {scheme}"); return RedirectToAction("Login"); } var email = result.Principal?.FindFirst(ClaimTypes.Email)?.Value; var name = result.Principal?.FindFirst(ClaimTypes.Name)?.Value; var providerId = result.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(providerId)) { _logger.LogWarning($"Missing required claims from {scheme} authentication"); return RedirectToAction("Login"); } // Find or create user var user = await _userService.GetUserByProviderAsync(scheme, providerId); if (user == null) { user = await _userService.CreateUserAsync(email, name ?? email, scheme, providerId); } else { await _userService.UpdateLastLoginAsync(user.Id); } // Create application claims var claims = new List { new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Email, user.Email), new Claim(ClaimTypes.Name, user.Name), new Claim("Provider", user.Provider), new Claim("IsPremium", user.IsPremium.ToString()) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30) }; await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); var returnUrl = result.Properties?.Items["returnUrl"] ?? "/"; return Redirect(returnUrl); } catch (Exception ex) { _logger.LogError(ex, $"Error in external login callback for {scheme}"); return RedirectToAction("Login"); } } [HttpPost] [Authorize] public async Task Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToAction("Index", "Home"); } [HttpGet] [Authorize] public async Task Profile() { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return RedirectToAction("Login"); } var user = await _userService.GetUserAsync(userId); if (user == null) { return RedirectToAction("Login"); } ViewBag.QRHistory = await _userService.GetUserQRHistoryAsync(userId, 10); ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId); ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId); return View(user); } [HttpGet] public async Task AdFreeStatus() { var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return Json(new AdFreeStatusViewModel { IsAdFree = false, TimeRemaining = 0, IsPremium = false }); } var shouldShowAds = await _adDisplayService.ShouldShowAds(userId); var isPremium = await _adDisplayService.HasValidPremiumSubscription(userId); var expiryDate = await _adDisplayService.GetAdFreeExpiryDate(userId); var status = await _adDisplayService.GetAdFreeStatusAsync(userId); return Json(new AdFreeStatusViewModel { IsAdFree = !shouldShowAds, TimeRemaining = isPremium ? int.MaxValue : 0, IsPremium = isPremium, ExpiryDate = expiryDate, SessionType = status }); } [HttpPost] [Authorize] public async Task ExtendAdFreeTime(int minutes) { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; // Método removido - sem extensão de tempo ad-free return Json(new { success = false, message = "Feature not available" }); } [HttpGet] [Authorize] public async Task History() { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return RedirectToAction("Login"); } var history = await _userService.GetUserQRHistoryAsync(userId, 50); return View(history); } [HttpPost] [Authorize] public async Task UpdatePreferences(string language) { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { return Json(new { success = false }); } try { var user = await _userService.GetUserAsync(userId); if (user != null) { user.PreferredLanguage = language; await _userService.UpdateUserAsync(user); return Json(new { success = true }); } } catch (Exception ex) { _logger.LogError(ex, $"Error updating preferences for user {userId}"); } return Json(new { success = false }); } } }