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;
using System.Linq;

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")
        {
            // 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<string> { "card" },
                Mode = "subscription",
                LineItems = new List<SessionLineItemOptions>
                {
                    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;
        }

        /// <summary>
        /// Creates a Stripe Checkout Session for an API subscription.
        /// Follows the same inline PriceData pattern used for credit purchases —
        /// no hardcoded Price IDs or appsettings entries.
        /// </summary>
        public async Task<string> CreateApiSubscriptionCheckoutAsync(
            string userId,
            ApiPlanTier planTier,
            string baseUrl)
        {
            var user = await _userService.GetUserAsync(userId);
            if (user == null) throw new InvalidOperationException("User not found");

            // Monthly prices in BRL (centavos) — no Price IDs, everything inline
            var (amountCents, productName) = planTier switch
            {
                ApiPlanTier.Starter  => (2900L,  "QRRapido API — Starter (50 req/min, 10 mil/mês)"),
                ApiPlanTier.Pro      => (9900L,  "QRRapido API — Pro (200 req/min, 100 mil/mês)"),
                ApiPlanTier.Business => (29900L, "QRRapido API — Business (500 req/min, 500 mil/mês)"),
                _ => throw new ArgumentException($"Plan tier '{planTier}' does not have a subscription price.")
            };

            var options = new SessionCreateOptions
            {
                PaymentMethodTypes = new List<string> { "card" },
                Mode = "subscription",
                LineItems = new List<SessionLineItemOptions>
                {
                    new SessionLineItemOptions
                    {
                        PriceData = new SessionLineItemPriceDataOptions
                        {
                            Currency   = "brl",
                            UnitAmount = amountCents,
                            Recurring  = new SessionLineItemPriceDataRecurringOptions
                            {
                                Interval = "month"
                            },
                            ProductData = new SessionLineItemPriceDataProductDataOptions
                            {
                                Name        = productName,
                                Description = $"Plano {ApiPlanLimits.PlanName(planTier)} — acesso à API QRRapido"
                            }
                        },
                        Quantity = 1
                    }
                },
                // Metadata on the Session (visible on checkout.session.completed)
                Metadata = new Dictionary<string, string>
                {
                    { "type",      "api_subscription" },
                    { "planTier",  planTier.ToString() },
                    { "userId",    userId }
                },
                // Metadata forwarded to the Subscription object (visible on subscription events)
                SubscriptionData = new SessionSubscriptionDataOptions
                {
                    Metadata = new Dictionary<string, string>
                    {
                        { "type",     "api_subscription" },
                        { "planTier", planTier.ToString() },
                        { "userId",   userId }
                    }
                },
                ClientReferenceId = userId,
                Customer          = !string.IsNullOrEmpty(user.StripeCustomerId) ? user.StripeCustomerId : null,
                SuccessUrl        = $"{baseUrl}/Developer?subscription=success",
                CancelUrl         = $"{baseUrl}/Developer/Pricing"
            };

            var service = new SessionService();
            var session = await service.CreateAsync(options);

            _logger.LogInformation(
                "API subscription checkout created: user={UserId} tier={Tier} sessionId={SessionId}",
                userId, planTier, session.Id);

            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)
                    {
                        // API subscription checkout — check metadata first
                        if (session.Mode == "subscription" &&
                            session.Metadata != null &&
                            session.Metadata.TryGetValue("type", out var sessionType) &&
                            sessionType == "api_subscription")
                        {
                            await ProcessApiSubscriptionCheckout(session);
                        }
                        // 1. Handle One-Time Payment (Credits)
                        else if (session.Mode == "payment" && session.PaymentStatus == "paid")
                        {
                            await ProcessCreditPayment(session);
                        }
                        // 2. Handle Subscription (Legacy QR premium)
                        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.updated":
                    if (stripeEvent.Data.Object is Subscription updatedSub &&
                        updatedSub.Metadata != null &&
                        updatedSub.Metadata.TryGetValue("type", out var updType) &&
                        updType == "api_subscription")
                    {
                        await ProcessApiSubscriptionUpdated(updatedSub);
                    }
                    break;

                case "customer.subscription.deleted":
                    if (stripeEvent.Data.Object is Subscription deletedSub)
                    {
                        if (deletedSub.Metadata != null &&
                            deletedSub.Metadata.TryGetValue("type", out var delType) &&
                            delType == "api_subscription")
                        {
                            // API subscription canceled — downgrade to Free
                            await _userService.UpdateApiSubscriptionStatusAsync(
                                deletedSub.Id, "canceled");
                        }
                        else
                        {
                            // Legacy QR premium subscription
                            await _userService.DeactivatePremiumStatus(deletedSub.Id);
                        }
                    }
                    break;

                case "invoice.payment_failed":
                    if (stripeEvent.Data.Object is Invoice failedInvoice)
                    {
                        // Get subscription ID from invoice line items (same pattern as invoice.finalized)
                        var failedLineItem = failedInvoice.Lines?.Data
                            .FirstOrDefault(line => !string.IsNullOrEmpty(line.SubscriptionId));

                        if (failedLineItem != null)
                        {
                            var subService = new SubscriptionService();
                            var failedSub  = await subService.GetAsync(failedLineItem.SubscriptionId);

                            if (failedSub?.Metadata != null &&
                                failedSub.Metadata.TryGetValue("type", out var failType) &&
                                failType == "api_subscription")
                            {
                                await _userService.UpdateApiSubscriptionStatusAsync(
                                    failedSub.Id, "past_due");

                                _logger.LogWarning(
                                    "API subscription payment failed: subId={SubId}", failedSub.Id);
                            }
                        }
                    }
                    break;
            }
        }

        private async Task ProcessApiSubscriptionCheckout(Session session)
        {
            if (session.Metadata == null ||
                !session.Metadata.TryGetValue("userId",   out var userId) ||
                !session.Metadata.TryGetValue("planTier", out var tierStr))
            {
                _logger.LogWarning("API subscription checkout completed but missing metadata: sessionId={Id}", session.Id);
                return;
            }

            if (!Enum.TryParse<ApiPlanTier>(tierStr, out var tier))
            {
                _logger.LogWarning("API subscription checkout has invalid planTier '{Tier}'", tierStr);
                return;
            }

            // Same pattern as existing ProcessSubscriptionActivation: fetch SubscriptionItem for period end
            var subscriptionService = new SubscriptionService();
            var subscription = await subscriptionService.GetAsync(session.SubscriptionId);

            var subItemService = new SubscriptionItemService();
            var subItem = subItemService.Get(subscription.Items.Data[0].Id);

            await _userService.ActivateApiSubscriptionAsync(
                userId,
                subscription.Id,
                tier,
                subItem.CurrentPeriodEnd,
                subscription.CustomerId);

            _logger.LogInformation(
                "API subscription activated via checkout: user={UserId} tier={Tier} subId={SubId}",
                userId, tier, subscription.Id);
        }

        private async Task ProcessApiSubscriptionUpdated(Subscription subscription)
        {
            // Re-read tier from metadata in case of a plan change (upgrade/downgrade via Stripe portal)
            ApiPlanTier? newTier = null;
            if (subscription.Metadata != null &&
                subscription.Metadata.TryGetValue("planTier", out var tierStr) &&
                Enum.TryParse<ApiPlanTier>(tierStr, out var parsedTier))
            {
                newTier = parsedTier;
            }

            var newStatus = subscription.Status switch
            {
                "active"   => "active",
                "past_due" => "past_due",
                "canceled" => "canceled",
                _          => subscription.Status
            };

            // Fetch current period end from SubscriptionItem (same pattern as existing code)
            DateTime? periodEnd = null;
            if (subscription.Items?.Data?.Count > 0)
            {
                var subItemService = new SubscriptionItemService();
                var subItem = subItemService.Get(subscription.Items.Data[0].Id);
                periodEnd = subItem.CurrentPeriodEnd;
            }

            await _userService.UpdateApiSubscriptionStatusAsync(
                subscription.Id,
                newStatus,
                newTier,
                periodEnd);

            _logger.LogInformation(
                "API subscription updated: subId={SubId} status={Status} tier={Tier}",
                subscription.Id, newStatus, newTier);
        }

        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<bool> 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<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
            {
                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.");
        }
    }
}