using BCards.Web.Models; using BCards.Web.Repositories; using BCards.Web.Services; using BCards.Web.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace BCards.Web.Controllers; [Authorize] public class PaymentController : Controller { private readonly IPaymentService _paymentService; private readonly IAuthService _authService; private readonly IUserRepository _userService; private readonly ISubscriptionRepository _subscriptionRepository; public PaymentController(IPaymentService paymentService, IAuthService authService, IUserRepository userService, ISubscriptionRepository subscriptionRepository) { _paymentService = paymentService; _authService = authService; _userService = userService; _subscriptionRepository = subscriptionRepository; } [HttpPost] public async Task CreateCheckoutSession(string planType) { var user = await _authService.GetCurrentUserAsync(User); if (user == null) return RedirectToAction("Login", "Auth"); var successUrl = Url.Action("Success", "Payment", null, Request.Scheme); var cancelUrl = Url.Action("Cancel", "Payment", null, Request.Scheme); TempData[$"PlanType|{user.Id}"] = planType; try { var checkoutUrl = await _paymentService.CreateCheckoutSessionAsync( user.Id, planType, successUrl!, cancelUrl!); return Redirect(checkoutUrl); } catch (Exception ex) { TempData["Error"] = $"Erro ao processar pagamento: {ex.Message}"; return RedirectToAction("Pricing", "Home"); } } public async Task Success() { var user = await _authService.GetCurrentUserAsync(User); var planType = TempData[$"PlanType|{user.Id}"].ToString(); try { if (!string.IsNullOrEmpty(planType) && Enum.TryParse(planType, out var plan)) { user.CurrentPlan = plan.ToString(); user.SubscriptionStatus = "active"; await _userService.UpdateAsync(user); // ou o método equivalente TempData["Success"] = $"Assinatura {planType} ativada com sucesso!"; } return RedirectToAction("Dashboard", "Admin"); } catch (Exception ex) { TempData["Error"] = $"Erro ao processar pagamento: {ex.Message}"; return RedirectToAction("Dashboard", "Admin"); } } public IActionResult Cancel() { TempData["Info"] = "Pagamento cancelado. Você pode tentar novamente quando quiser."; return RedirectToAction("Pricing", "Home"); } [HttpPost] [Route("webhook/stripe")] [AllowAnonymous] public async Task StripeWebhook() { var signature = Request.Headers["Stripe-Signature"].FirstOrDefault(); if (string.IsNullOrEmpty(signature)) return BadRequest(); string requestBody; using (var reader = new StreamReader(Request.Body)) { requestBody = await reader.ReadToEndAsync(); } try { await _paymentService.HandleWebhookAsync(requestBody, signature); return Ok(); } catch (Exception ex) { return BadRequest($"Webhook error: {ex.Message}"); } } public async Task ManageSubscription() { var user = await _authService.GetCurrentUserAsync(User); if (user == null) return RedirectToAction("Login", "Auth"); try { var viewModel = new ManageSubscriptionViewModel { User = user, StripeSubscription = await _paymentService.GetSubscriptionDetailsAsync(user.Id), PaymentHistory = await _paymentService.GetPaymentHistoryAsync(user.Id), AvailablePlans = GetAvailablePlans(user.CurrentPlan) }; // Pegar assinatura local se existir if (!string.IsNullOrEmpty(user.StripeCustomerId)) { // Aqui você poderia buscar a subscription local se necessário // viewModel.LocalSubscription = await _subscriptionRepository.GetByUserIdAsync(user.Id); } return View(viewModel); } catch (Exception ex) { var errorViewModel = new ManageSubscriptionViewModel { User = user, ErrorMessage = $"Erro ao carregar dados da assinatura: {ex.Message}", AvailablePlans = GetAvailablePlans(user.CurrentPlan) }; return View(errorViewModel); } } [HttpPost] public async Task CancelSubscription(string subscriptionId) { try { await _paymentService.CancelSubscriptionAsync(subscriptionId); TempData["Success"] = "Sua assinatura será cancelada no final do período atual."; } catch (Exception ex) { TempData["Error"] = $"Erro ao cancelar assinatura: {ex.Message}"; } return RedirectToAction("ManageSubscription"); } [HttpPost] public async Task ChangePlan(string newPlanType) { var user = await _authService.GetCurrentUserAsync(User); if (user == null) return RedirectToAction("Login", "Auth"); try { // Para mudanças de plano, vamos usar o Stripe Checkout var returnUrl = Url.Action("ManageSubscription", "Payment", null, Request.Scheme); var cancelUrl = Url.Action("ManageSubscription", "Payment", null, Request.Scheme); var checkoutUrl = await _paymentService.CreateCheckoutSessionAsync( user.Id, newPlanType, returnUrl!, cancelUrl!); return Redirect(checkoutUrl); } catch (Exception ex) { TempData["Error"] = $"Erro ao alterar plano: {ex.Message}"; return RedirectToAction("ManageSubscription"); } } [HttpPost] public async Task OpenStripePortal() { var user = await _authService.GetCurrentUserAsync(User); if (user == null || string.IsNullOrEmpty(user.StripeCustomerId)) { TempData["Error"] = "Erro: dados de assinatura não encontrados."; return RedirectToAction("ManageSubscription"); } try { var returnUrl = Url.Action("ManageSubscription", "Payment", null, Request.Scheme); var portalUrl = await _paymentService.CreatePortalSessionAsync(user.StripeCustomerId, returnUrl!); return Redirect(portalUrl); } catch (Exception ex) { TempData["Error"] = $"Erro ao abrir portal de pagamento: {ex.Message}"; return RedirectToAction("ManageSubscription"); } } private List GetAvailablePlans(string currentPlan) { var plans = new List { new() { PlanType = "basic", DisplayName = "Básico", Price = 9.90m, PriceId = "price_basic", // Substitua pelos IDs reais do Stripe MaxLinks = 5, AllowAnalytics = true, Features = new List { "5 links", "Temas básicos", "Análises básicas" }, IsCurrentPlan = currentPlan == "basic" }, new() { PlanType = "professional", DisplayName = "Profissional", Price = 24.90m, PriceId = "price_professional", // Substitua pelos IDs reais do Stripe MaxLinks = 15, AllowAnalytics = true, AllowCustomDomain = true, Features = new List { "15 links", "Todos os temas", "Domínio personalizado", "Análises avançadas" }, IsCurrentPlan = currentPlan == "professional" }, new() { PlanType = "premium", DisplayName = "Premium", Price = 29.90m, PriceId = "price_premium", // Substitua pelos IDs reais do Stripe MaxLinks = -1, // Ilimitado AllowCustomThemes = true, AllowAnalytics = true, AllowCustomDomain = true, Features = new List { "Links ilimitados", "Temas personalizados", "Múltiplos domínios", "Suporte prioritário" }, IsCurrentPlan = currentPlan == "premium" } }; // Marcar upgrades e downgrades var currentPlanIndex = plans.FindIndex(p => p.IsCurrentPlan); for (int i = 0; i < plans.Count; i++) { if (i > currentPlanIndex) plans[i].IsUpgrade = true; else if (i < currentPlanIndex) plans[i].IsDowngrade = true; } return plans; } }