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") { // Legacy subscription method - Kept for compatibility but likely unused in Credit model var user = await _userService.GetUserAsync(userId); if (user == null) throw new Exception("User not found"); var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, Mode = "subscription", LineItems = new List { new SessionLineItemOptions { Price = priceId, Quantity = 1 } }, Customer = user.StripeCustomerId, // Might be null, legacy logic handled creation ClientReferenceId = userId, SuccessUrl = $"{_config["App:BaseUrl"]}/Pagamento/Sucesso", CancelUrl = $"{_config["App:BaseUrl"]}/Pagamento/SelecaoPlano", }; var service = new SessionService(); var session = await service.CreateAsync(options); 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": if (stripeEvent.Data.Object is Session session) { // 1. Handle One-Time Payment (Credits) if (session.Mode == "payment" && session.PaymentStatus == "paid") { await ProcessCreditPayment(session); } // 2. Handle Subscription (Legacy) else if (session.SubscriptionId != null) { var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.GetAsync(session.SubscriptionId); var userId = session.ClientReferenceId ?? (session.Metadata != null && session.Metadata.ContainsKey("user_id") ? session.Metadata["user_id"] : null); if (!string.IsNullOrEmpty(userId)) { await ProcessSubscriptionActivation(userId, subscription); } } } break; case "invoice.finalized": // Legacy subscription logic if (stripeEvent.Data.Object is Invoice invoice) { var subscriptionLineItem = invoice.Lines?.Data .FirstOrDefault(line => !string.IsNullOrEmpty(line.SubscriptionId)); if (subscriptionLineItem != null) { var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.GetAsync(subscriptionLineItem.SubscriptionId); var user = await _userService.GetUserByStripeCustomerIdAsync(subscription.CustomerId); if (user != null) { await ProcessSubscriptionActivation(user.Id, subscription); } } } break; case "customer.subscription.deleted": if (stripeEvent.Data.Object is Subscription deletedSubscription) { await _userService.DeactivatePremiumStatus(deletedSubscription.Id); } break; } } private async Task ProcessCreditPayment(Session session) { if (session.Metadata != null && session.Metadata.TryGetValue("user_id", out var userId) && session.Metadata.TryGetValue("credits_amount", out var creditsStr) && int.TryParse(creditsStr, out var credits)) { var success = await _userService.AddCreditsAsync(userId, credits); if (success) { _logger.LogInformation($"✅ Credits added via Stripe: {credits} credits for user {userId}"); } else { _logger.LogError($"❌ Failed to add credits for user {userId}"); } } else { _logger.LogWarning("⚠️ Payment received but missing metadata (user_id or credits_amount)"); } } private async Task ProcessSubscriptionActivation(string userId, Subscription subscription) { var service = new SubscriptionItemService(); var subItem = service.Get(subscription.Items.Data[0].Id); var user = await _userService.GetUserAsync(userId); if (user == null) return; if (string.IsNullOrEmpty(user.StripeCustomerId)) { await _userService.UpdateUserStripeCustomerIdAsync(user.Id, subscription.CustomerId); } await _userService.ActivatePremiumStatus(userId, subscription.Id, subItem.CurrentPeriodEnd); } // Helper methods for legacy support public async Task CancelSubscriptionAsync(string subscriptionId) { try { var service = new SubscriptionService(); await service.CancelAsync(subscriptionId, new SubscriptionCancelOptions()); return true; } catch { return false; } } public async Task DeactivatePremiumStatus(string subscriptionId) => await _userService.DeactivatePremiumStatus(subscriptionId); 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 { return "Unknown"; } } public async Task<(bool success, string message)> CancelAndRefundSubscriptionAsync(string userId) { // Legacy method - no longer applicable for credit system return (false, "Sistema migrado para créditos. Entre em contato com o suporte."); } } }