using Stripe; using Stripe.Checkout; using QRRapidoApp.Models; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System; namespace QRRapidoApp.Services { public class StripeService { private readonly IConfiguration _config; private readonly IUserService _userService; private readonly ILogger _logger; public StripeService(IConfiguration config, IUserService userService, ILogger logger) { _config = config; _userService = userService; _logger = logger; StripeConfiguration.ApiKey = _config["Stripe:SecretKey"]; } public async Task CreateCheckoutSessionAsync(string userId, string priceId, string lang = "pt-BR") { var user = await _userService.GetUserAsync(userId); if (user == null) { throw new Exception("User not found"); } var customerId = user.StripeCustomerId; if (string.IsNullOrEmpty(customerId)) { var customerOptions = new CustomerCreateOptions { Email = user.Email, Name = user.Name, Metadata = new Dictionary { { "app_user_id", user.Id } } }; var customerService = new CustomerService(); var customer = await customerService.CreateAsync(customerOptions); customerId = customer.Id; await _userService.UpdateUserStripeCustomerIdAsync(userId, customerId); } var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, Mode = "subscription", LineItems = new List { new SessionLineItemOptions { Price = priceId, Quantity = 1 } }, Customer = customerId, ClientReferenceId = userId, SuccessUrl = $"{_config["App:BaseUrl"]}/Pagamento/Sucesso", CancelUrl = $"{_config["App:BaseUrl"]}/{lang}/Pagamento/SelecaoPlano", AllowPromotionCodes = true, Metadata = new Dictionary { { "user_id", userId } } }; var service = new SessionService(); var session = await service.CreateAsync(options); _logger.LogInformation($"Created Stripe checkout session {session.Id} for user {userId}"); return session.Url; } public async Task HandleWebhookAsync(string json, string signature) { var webhookSecret = _config["Stripe:WebhookSecret"]; var stripeEvent = EventUtility.ConstructEvent(json, signature, webhookSecret); _logger.LogInformation($"Processing Stripe webhook: {stripeEvent.Type}"); switch (stripeEvent.Type) { case "checkout.session.completed": var session = stripeEvent.Data.Object as Session; if (session?.SubscriptionId != null) { var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.GetAsync(session.SubscriptionId); await ProcessSubscriptionActivation(session.ClientReferenceId, subscription); } break; case "invoice.finalized": var invoice = stripeEvent.Data.Object as Invoice; var subscriptionLineItem = invoice.Lines?.Data .FirstOrDefault(line => !string.IsNullOrEmpty(line.SubscriptionId) || line.Subscription != null ); string subscriptionId = null; if (subscriptionLineItem != null) { // Tenta obter o ID da assinatura de duas formas diferentes subscriptionId = subscriptionLineItem.SubscriptionId ?? subscriptionLineItem.Subscription?.Id; } if (subscriptionId != null) { var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.GetAsync(subscriptionId); var user = await _userService.GetUserByStripeCustomerIdAsync(subscription.CustomerId); if (user != null) { await ProcessSubscriptionActivation(user.Id, subscription); } } break; case "customer.subscription.deleted": var deletedSubscription = stripeEvent.Data.Object as Subscription; if (deletedSubscription != null) { await _userService.DeactivatePremiumStatus(deletedSubscription.Id); } break; default: _logger.LogWarning($"Unhandled Stripe webhook event type: {stripeEvent.Type}"); break; } } private async Task ProcessSubscriptionActivation(string userId, Subscription subscription) { var service = new SubscriptionItemService(); var subItem = service.Get(subscription.Items.Data[0].Id); if (string.IsNullOrEmpty(userId) || subscription == null) { _logger.LogWarning("Could not process subscription activation due to missing userId or subscription data."); return; } var user = await _userService.GetUserAsync(userId); if (user == null) { _logger.LogWarning($"User not found for premium activation: {userId}"); return; } if (string.IsNullOrEmpty(user.StripeCustomerId)) { await _userService.UpdateUserStripeCustomerIdAsync(user.Id, subscription.CustomerId); } await _userService.ActivatePremiumStatus(userId, subscription.Id, subItem.CurrentPeriodEnd); _logger.LogInformation($"Successfully processed premium activation/renewal for user {userId}."); } public async Task GetSubscriptionStatusAsync(string? subscriptionId) { if (string.IsNullOrEmpty(subscriptionId)) return "None"; try { var service = new SubscriptionService(); var subscription = await service.GetAsync(subscriptionId); return subscription.Status; } catch (Exception ex) { _logger.LogError(ex, $"Error getting subscription status for {subscriptionId}"); return "Unknown"; } } public async Task CancelSubscriptionAsync(string subscriptionId) { try { var service = new SubscriptionService(); await service.CancelAsync(subscriptionId, new SubscriptionCancelOptions()); _logger.LogInformation($"Canceled subscription {subscriptionId} via API."); return true; } catch (Exception ex) { _logger.LogError(ex, $"Error canceling subscription {subscriptionId}"); return false; } } } }