using MongoDB.Driver;
using QRRapidoApp.Data;
using QRRapidoApp.Models;
using QRRapidoApp.Models.ViewModels;
using System.Text.Json;

namespace QRRapidoApp.Services
{
    public class UserService : IUserService
    {
        private readonly MongoDbContext _context;
        private readonly IConfiguration _config;
        private readonly ILogger<UserService> _logger;

        public UserService(MongoDbContext context, IConfiguration config, ILogger<UserService> logger)
        {
            _context = context;
            _config = config;
            _logger = logger;
        }

        public async Task<User?> GetUserAsync(string userId)
        {
            try
            {
                if (_context.Users == null) return null; // Development mode without MongoDB
                User? userData = null;
                
                if (!String.IsNullOrEmpty(userId))
                {
                    userData = await _context.Users.Find(u => u.Id == userId).FirstOrDefaultAsync();
                }

                return userData ?? new User();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting user {userId}: {ex.Message}");
                return null;
            }
        }

        public async Task<User?> GetUserByEmailAsync(string email)
        {
            try
            {
                if (_context.Users == null) return null; // Development mode without MongoDB
                
                return await _context.Users.Find(u => u.Email == email).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting user by email {email}: {ex.Message}");
                return null;
            }
        }

        public async Task<User?> GetUserByProviderAsync(string provider, string providerId)
        {
            try
            {
                return await _context.Users
                    .Find(u => u.Provider == provider && u.ProviderId == providerId)
                    .FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting user by provider {provider}:{providerId}: {ex.Message}");
                return null;
            }
        }

        public async Task<User> CreateUserAsync(string email, string name, string provider, string providerId)
        {
            var user = new User
            {
                Email = email,
                Name = name,
                Provider = provider,
                ProviderId = providerId,
                CreatedAt = DateTime.UtcNow,
                LastLoginAt = DateTime.UtcNow,
                PreferredLanguage = "pt-BR",
                DailyQRCount = 0,
                LastQRDate = DateTime.UtcNow.Date,
                TotalQRGenerated = 0
            };

            await _context.Users.InsertOneAsync(user);
            _logger.LogInformation($"Created new user: {email} via {provider}");

            return user;
        }

        public async Task UpdateLastLoginAsync(string userId)
        {
            try
            {
                var update = Builders<User>.Update
                    .Set(u => u.LastLoginAt, DateTime.UtcNow);

                await _context.Users.UpdateOneAsync(u => u.Id == userId, update);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error updating last login for user {userId}: {ex.Message}");
            }
        }

        public async Task<bool> UpdateUserAsync(User user)
        {
            try
            {
                var result = await _context.Users.ReplaceOneAsync(u => u.Id == user.Id, user);
                return result.ModifiedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error updating user {user.Id}: {ex.Message}");
                return false;
            }
        }

        public async Task<int> GetDailyQRCountAsync(string? userId)
        {
            if (string.IsNullOrEmpty(userId))
                return 0; // Anonymous users tracked separately

            try
            {
                var user = await GetUserAsync(userId);
                if (user == null) return 0;

                // Reset count if it's a new day
                if (user.LastQRDate.Date < DateTime.UtcNow.Date)
                {
                    user.DailyQRCount = 0;
                    user.LastQRDate = DateTime.UtcNow.Date;
                    await UpdateUserAsync(user);
                }

                return user.DailyQRCount;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting daily QR count for user {userId}: {ex.Message}");
                return 0;
            }
        }

        public async Task<int> IncrementDailyQRCountAsync(string userId)
        {
            try
            {
                var user = await GetUserAsync(userId);
                if (user == null) return 0;

                // Reset count if it's a new day
                if (user.LastQRDate.Date < DateTime.UtcNow.Date)
                {
                    user.DailyQRCount = 1;
                    user.LastQRDate = DateTime.UtcNow.Date;
                }
                else
                {
                    user.DailyQRCount++;
                }

                user.TotalQRGenerated++;
                await UpdateUserAsync(user);

                // Premium and logged users have unlimited QR codes
                return int.MaxValue;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error incrementing daily QR count for user {userId}: {ex.Message}");
                return 0;
            }
        }

        public async Task<int> GetRemainingQRCountAsync(string userId)
        {
            try
            {
                var user = await GetUserAsync(userId);
                if (user == null) return 0;

                // Premium users have unlimited
                if (user.IsPremium) return int.MaxValue;

                // Logged users (non-premium) have unlimited
                return int.MaxValue;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting remaining QR count for user {userId}: {ex.Message}");
                return 0;
            }
        }

        public async Task<bool> CanGenerateQRAsync(string? userId, bool isPremium)
        {
            // Premium users have unlimited QR codes
            if (isPremium) return true;
            
            // Logged users (non-premium) have unlimited QR codes
            if (!string.IsNullOrEmpty(userId)) return true;

            // Anonymous users have 3 QR codes per day
            var dailyCount = await GetDailyQRCountAsync(userId);
            var limit = 3;

            return dailyCount < limit;
        }

        public async Task SaveQRToHistoryAsync(string? userId, QRGenerationResult qrResult)
        {
            try
            {
                var qrHistory = new QRCodeHistory
                {
                    UserId = userId,
                    Type = qrResult.RequestSettings?.Type ?? "unknown",
                    Content = qrResult.RequestSettings?.Content ?? "",
                    QRCodeBase64 = qrResult.QRCodeBase64,
                    CustomizationSettings = JsonSerializer.Serialize(qrResult.RequestSettings),
                    CreatedAt = DateTime.UtcNow,
                    Language = qrResult.RequestSettings?.Language ?? "pt-BR",
                    Size = qrResult.RequestSettings?.Size ?? 300,
                    GenerationTimeMs = qrResult.GenerationTimeMs,
                    FromCache = qrResult.FromCache,
                    IsActive = true,
                    LastAccessedAt = DateTime.UtcNow,
                    TrackingId = qrResult.TrackingId, // Save tracking ID for analytics
                    IsDynamic = !string.IsNullOrEmpty(qrResult.TrackingId) // Mark as dynamic if tracking is enabled
                };

                await _context.QRCodeHistory.InsertOneAsync(qrHistory);

                // Update user's QR history IDs if logged in
                if (!string.IsNullOrEmpty(userId))
                {
                    var update = Builders<User>.Update
                        .Push(u => u.QRHistoryIds, qrHistory.Id);
                    await _context.Users.UpdateOneAsync(u => u.Id == userId, update);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error saving QR to history: {ex.Message}");
            }
        }

        public async Task<List<QRCodeHistory>> GetUserQRHistoryAsync(string userId, int limit = 50)
        {
            try
            {
                return await _context.QRCodeHistory
                    .Find(q => q.UserId == userId && q.IsActive)
                    .SortByDescending(q => q.CreatedAt)
                    .Limit(limit)
                    .ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting QR history for user {userId}: {ex.Message}");
                return new List<QRCodeHistory>();
            }
        }

        public async Task<QRCodeHistory?> GetQRDataAsync(string qrId)
        {
            try
            {
                return await _context.QRCodeHistory
                    .Find(q => q.Id == qrId && q.IsActive)
                    .FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting QR data {qrId}: {ex.Message}");
                return null;
            }
        }

        public async Task<bool> DeleteQRFromHistoryAsync(string userId, string qrId)
        {
            try
            {
                // First verify that the QR code belongs to the user
                var qrCode = await _context.QRCodeHistory
                    .Find(q => q.Id == qrId && q.UserId == userId && q.IsActive)
                    .FirstOrDefaultAsync();

                if (qrCode == null)
                {
                    _logger.LogWarning($"QR code not found or doesn't belong to user - QRId: {qrId}, UserId: {userId}");
                    return false;
                }

                // Soft delete: mark as inactive instead of permanently deleting
                var update = Builders<QRCodeHistory>.Update.Set(q => q.IsActive, false);
                var result = await _context.QRCodeHistory.UpdateOneAsync(
                    q => q.Id == qrId && q.UserId == userId, 
                    update);

                return result.ModifiedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error deleting QR from history - QRId: {qrId}, UserId: {userId}: {ex.Message}");
                return false;
            }
        }

        public async Task<int> GetQRCountThisMonthAsync(string userId)
        {
            try
            {
                var startOfMonth = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1);
                var endOfMonth = startOfMonth.AddMonths(1);

                var count = await _context.QRCodeHistory
                    .CountDocumentsAsync(q => q.UserId == userId && 
                                           q.CreatedAt >= startOfMonth && 
                                           q.CreatedAt < endOfMonth);

                return (int)count;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting monthly QR count for user {userId}: {ex.Message}");
                return 0;
            }
        }

        // MÉTODO REMOVIDO: ExtendAdFreeTimeAsync - não é mais necessário

        public async Task<string> GetUserEmailAsync(string userId)
        {
            var user = await GetUserAsync(userId);
            return user?.Email ?? string.Empty;
        }

        public async Task MarkPremiumCancelledAsync(string userId, DateTime cancelledAt)
        {
            try
            {
                if (_context.Users == null) return; // Development mode without MongoDB

                var update = Builders<User>.Update
                    .Set(u => u.IsPremium, false)
                    .Set(u => u.PremiumCancelledAt, cancelledAt)
                    .Set(u => u.PremiumExpiresAt, null);

                await _context.Users.UpdateOneAsync(u => u.Id == userId, update);
                
                _logger.LogInformation($"Marked premium as cancelled for user {userId} at {cancelledAt}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error marking premium cancelled for user {userId}: {ex.Message}");
            }
        }

        public async Task<List<User>> GetUsersForHistoryCleanupAsync(DateTime cutoffDate)
        {
            try
            {
                if (_context.Users == null) return new List<User>(); // Development mode without MongoDB

                return await _context.Users
                    .Find(u => u.PremiumCancelledAt != null && 
                              u.PremiumCancelledAt < cutoffDate &&
                              u.QRHistoryIds.Count > 0)
                    .ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error getting users for history cleanup: {ex.Message}");
                return new List<User>();
            }
        }

        public async Task DeleteUserHistoryAsync(string userId)
        {
            try
            {
                if (_context.Users == null || _context.QRCodeHistory == null) return; // Development mode without MongoDB

                var user = await GetUserAsync(userId);
                if (user?.QRHistoryIds?.Any() == true)
                {
                    // Remover histórico de QR codes
                    await _context.QRCodeHistory.DeleteManyAsync(qr => user.QRHistoryIds.Contains(qr.Id));
                    
                    // Limpar lista de histórico do usuário
                    var update = Builders<User>.Update.Set(u => u.QRHistoryIds, new List<string>());
                    await _context.Users.UpdateOneAsync(u => u.Id == userId, update);
                    
                    _logger.LogInformation($"Deleted history for user {userId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error deleting history for user {userId}: {ex.Message}");
            }
        }

        public async Task ActivatePremiumStatus(string userId, string stripeSubscriptionId, DateTime expiryDate)
        {
            // Verifica se é uma nova assinatura (não renovação)
            var user = await GetUserAsync(userId);
            var isNewSubscription = user?.StripeSubscriptionId != stripeSubscriptionId;

            var updateBuilder = Builders<User>.Update
                .Set(u => u.IsPremium, true)
                .Set(u => u.StripeSubscriptionId, stripeSubscriptionId)
                .Set(u => u.PremiumExpiresAt, expiryDate)
                .Unset(u => u.PremiumCancelledAt);

            // Se é nova assinatura, atualiza a data de início (para CDC 7 dias)
            if (isNewSubscription)
            {
                updateBuilder = updateBuilder.Set(u => u.SubscriptionStartedAt, DateTime.UtcNow);
            }

            await _context.Users.UpdateOneAsync(u => u.Id == userId, updateBuilder);
            _logger.LogInformation($"Activated premium for user {userId} (new subscription: {isNewSubscription})");
        }

        public async Task DeactivatePremiumStatus(string stripeSubscriptionId)
        {
            var update = Builders<User>.Update
                .Set(u => u.IsPremium, false)
                .Set(u => u.PremiumCancelledAt, DateTime.UtcNow);

            await _context.Users.UpdateOneAsync(u => u.StripeSubscriptionId == stripeSubscriptionId, update);
            _logger.LogInformation($"Deactivated premium for subscription {stripeSubscriptionId}");
        }

        public async Task<User?> GetUserByStripeCustomerIdAsync(string customerId)
        {
            return await _context.Users.Find(u => u.StripeCustomerId == customerId).FirstOrDefaultAsync();
        }

        public async Task UpdateUserStripeCustomerIdAsync(string userId, string stripeCustomerId)
        {
            var update = Builders<User>.Update.Set(u => u.StripeCustomerId, stripeCustomerId);
            await _context.Users.UpdateOneAsync(u => u.Id == userId, update);
        }

        /// <summary>
        /// Get QR code by tracking ID (for analytics)
        /// </summary>
        public async Task<QRCodeHistory?> GetQRByTrackingIdAsync(string trackingId)
        {
            try
            {
                return await _context.QRCodeHistory
                    .Find(q => q.TrackingId == trackingId && q.IsActive)
                    .FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting QR by tracking ID {TrackingId}: {ErrorMessage}", trackingId, ex.Message);
                return null;
            }
        }

        /// <summary>
        /// Increment scan count for QR code analytics
        /// </summary>
        public async Task IncrementQRScanCountAsync(string trackingId)
        {
            try
            {
                var filter = Builders<QRCodeHistory>.Filter.Eq(q => q.TrackingId, trackingId);
                var update = Builders<QRCodeHistory>.Update
                    .Inc(q => q.ScanCount, 1)
                    .Set(q => q.LastAccessedAt, DateTime.UtcNow);

                var result = await _context.QRCodeHistory.UpdateOneAsync(filter, update);

                if (result.ModifiedCount > 0)
                {
                    _logger.LogDebug("QR scan count incremented - TrackingId: {TrackingId}", trackingId);
                }
                else
                {
                    _logger.LogWarning("Failed to increment scan count - TrackingId not found: {TrackingId}", trackingId);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error incrementing scan count for {TrackingId}: {ErrorMessage}", trackingId, ex.Message);
            }
        }
    }
}