
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<StripeService> _logger;

        public StripeService(IConfiguration config, IUserService userService, ILogger<StripeService> logger)
        {
            _config = config;
            _userService = userService;
            _logger = logger;
            StripeConfiguration.ApiKey = _config["Stripe:SecretKey"];
        }

        public async Task<string> 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;
            var customerService = new CustomerService();

            // Verify if customer exists in Stripe, create new if not
            if (!string.IsNullOrEmpty(customerId))
            {
                try
                {
                    // Try to retrieve the customer to verify it exists
                    await customerService.GetAsync(customerId);
                    _logger.LogInformation($"Using existing Stripe customer {customerId} for user {userId}");
                }
                catch (StripeException ex) when (ex.StripeError?.Code == "resource_missing")
                {
                    _logger.LogWarning($"Stripe customer {customerId} not found, creating new one for user {userId}");
                    customerId = null; // Force creation of new customer
                }
            }

            if (string.IsNullOrEmpty(customerId))
            {
                var customerOptions = new CustomerCreateOptions
                {
                    Email = user.Email,
                    Name = user.Name,
                    Metadata = new Dictionary<string, string> { { "app_user_id", user.Id } }
                };
                var customer = await customerService.CreateAsync(customerOptions);
                customerId = customer.Id;
                await _userService.UpdateUserStripeCustomerIdAsync(userId, customerId);
                _logger.LogInformation($"Created new Stripe customer {customerId} for user {userId}");
            }

            var options = new SessionCreateOptions
            {
                PaymentMethodTypes = new List<string> { "card" },
                Mode = "subscription",
                LineItems = new List<SessionLineItemOptions>
                {
                    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<string, string> { { "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<string> 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<bool> 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;
            }
        }

        /// <summary>
        /// Verifica se a assinatura está dentro do período de 7 dias para reembolso (CDC)
        /// </summary>
        public bool IsEligibleForRefund(DateTime? subscriptionStartedAt)
        {
            if (!subscriptionStartedAt.HasValue)
            {
                return false;
            }

            var daysSinceSubscription = (DateTime.UtcNow - subscriptionStartedAt.Value).TotalDays;
            return daysSinceSubscription <= 7;
        }

        /// <summary>
        /// Cancela assinatura E processa reembolso total (CDC - 7 dias)
        /// </summary>
        public async Task<(bool success, string message)> CancelAndRefundSubscriptionAsync(string userId)
        {
            try
            {
                var user = await _userService.GetUserAsync(userId);
                if (user == null)
                {
                    return (false, "Usuário não encontrado");
                }

                if (string.IsNullOrEmpty(user.StripeSubscriptionId))
                {
                    return (false, "Nenhuma assinatura ativa encontrada");
                }

                // Verifica elegibilidade para reembolso
                if (!IsEligibleForRefund(user.SubscriptionStartedAt))
                {
                    var daysSince = user.SubscriptionStartedAt.HasValue
                        ? (DateTime.UtcNow - user.SubscriptionStartedAt.Value).TotalDays
                        : 0;
                    return (false, $"Período de reembolso de 7 dias expirado (assinatura criada há {Math.Round(daysSince, 1)} dias). Você ainda pode cancelar a renovação.");
                }

                // Busca a assinatura no Stripe
                var subscriptionService = new SubscriptionService();
                var subscription = await subscriptionService.GetAsync(user.StripeSubscriptionId);

                if (subscription == null)
                {
                    return (false, "Assinatura não encontrada no Stripe");
                }

                // Cancela a assinatura primeiro
                await subscriptionService.CancelAsync(subscription.Id, new SubscriptionCancelOptions());

                // Busca o último pagamento (invoice) desta assinatura para reembolsar
                var invoiceService = new InvoiceService();
                var invoiceListOptions = new InvoiceListOptions
                {
                    Subscription = subscription.Id,
                    Limit = 1,
                    Status = "paid"
                };
                var invoices = await invoiceService.ListAsync(invoiceListOptions);
                var latestInvoice = invoices.Data.FirstOrDefault();

                if (latestInvoice == null || latestInvoice.AmountPaid <= 0)
                {
                    // Mesmo sem invoice, cancela e desativa
                    await _userService.DeactivatePremiumStatus(subscription.Id);
                    return (true, "Assinatura cancelada com sucesso. Nenhum pagamento para reembolsar foi encontrado.");
                }

                // Processa o reembolso - Stripe reembolsa automaticamente o último pagamento
                var refundService = new RefundService();
                var refundOptions = new RefundCreateOptions
                {
                    Amount = latestInvoice.AmountPaid, // Reembolso total
                    Reason = RefundReasons.RequestedByCustomer,
                    Metadata = new Dictionary<string, string>
                    {
                        { "user_id", userId },
                        { "subscription_id", subscription.Id },
                        { "invoice_id", latestInvoice.Id },
                        { "refund_reason", "CDC 7 dias - Direito de arrependimento" }
                    }
                };

                // Stripe automaticamente encontra o charge/payment_intent correto através do subscription_id no metadata
                // Alternativamente, podemos buscar o último charge da subscription
                try
                {
                    // Tenta reembolsar usando a subscription (Stripe encontra o charge automaticamente)
                    var chargeService = new ChargeService();
                    var chargeOptions = new ChargeListOptions
                    {
                        Limit = 1,
                        Customer = subscription.CustomerId
                    };
                    var charges = await chargeService.ListAsync(chargeOptions);
                    var lastCharge = charges.Data.FirstOrDefault();

                    if (lastCharge != null)
                    {
                        refundOptions.Charge = lastCharge.Id;
                        var refund = await refundService.CreateAsync(refundOptions);

                        if (refund.Status == "succeeded" || refund.Status == "pending")
                        {
                            // Desativa o premium imediatamente no caso de reembolso
                            await _userService.DeactivatePremiumStatus(subscription.Id);

                            _logger.LogInformation($"Successfully refunded and canceled subscription {subscription.Id} for user {userId}. Refund ID: {refund.Id}");

                            return (true, $"Reembolso processado com sucesso! Você receberá R$ {(latestInvoice.AmountPaid / 100.0):F2} de volta em 5-10 dias úteis.");
                        }
                        else
                        {
                            _logger.LogWarning($"Refund failed with status {refund.Status} for subscription {subscription.Id}");
                            await _userService.DeactivatePremiumStatus(subscription.Id);
                            return (false, "Falha ao processar reembolso, mas assinatura foi cancelada. Entre em contato com o suporte.");
                        }
                    }
                    else
                    {
                        await _userService.DeactivatePremiumStatus(subscription.Id);
                        return (false, "Assinatura cancelada, mas nenhuma cobrança encontrada para reembolsar. Entre em contato com o suporte.");
                    }
                }
                catch (StripeException refundEx)
                {
                    _logger.LogError(refundEx, $"Error creating refund for subscription {subscription.Id}");
                    await _userService.DeactivatePremiumStatus(subscription.Id);
                    return (false, $"Assinatura cancelada, mas erro ao processar reembolso: {refundEx.Message}. Entre em contato com o suporte.");
                }
            }
            catch (StripeException ex)
            {
                _logger.LogError(ex, $"Stripe error during refund for user {userId}: {ex.Message}");
                return (false, $"Erro ao processar reembolso: {ex.StripeError?.Message ?? ex.Message}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error processing refund for user {userId}");
                return (false, "Erro inesperado ao processar reembolso. Tente novamente mais tarde.");
            }
        }
    }
}
