using MediatR; using FluentResults; using Microsoft.EntityFrameworkCore; using NexusReader.Application.DTOs.User; using NexusReader.Data.Persistence; namespace NexusReader.Application.Queries.User; public class GetUserProfileQueryHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; public GetUserProfileQueryHandler(IDbContextFactory dbContextFactory) { _dbContextFactory = dbContextFactory; } public async Task> Handle(GetUserProfileQuery request, CancellationToken cancellationToken) { using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); var profile = await dbContext.Users .Where(u => u.Id == request.UserId) .Select(u => new UserProfileDto { Email = u.Email ?? string.Empty, UserId = u.Id, AITokensUsed = u.AITokensUsed, TenantId = u.TenantId != null && u.TenantId.Length == 36 ? new Guid(u.TenantId) : Guid.Empty, Plan = u.SubscriptionPlan != null ? new SubscriptionPlanDto { Id = u.SubscriptionPlan.Id, Name = u.SubscriptionPlan.PlanName, AITokenLimit = u.SubscriptionPlan.AITokenLimit, MonthlyPrice = u.SubscriptionPlan.MonthlyPrice } : new SubscriptionPlanDto(), AverageQuizScore = u.QuizResults.Any(q => q.TotalQuestions > 0) ? (int)u.QuizResults.Where(q => q.TotalQuestions > 0).Average(q => (double)q.Score / q.TotalQuestions * 100) : 0, DisplayName = u.DisplayName, BooksReadCount = u.Ebooks.Count(), ConceptsMappedCount = dbContext.KnowledgeUnits.Count(k => k.TenantId == u.TenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId)), LastReadBook = u.Ebooks.OrderByDescending(e => e.LastReadDate).Select(e => new LastReadBookDto { Id = e.Id, Title = e.Title, Author = new AuthorDto { Id = e.Author.Id, Name = e.Author.Name }, CoverUrl = e.CoverUrl, Progress = e.Progress, LastChapter = e.LastChapter ?? "Rozpoczynanie...", LastChapterIndex = e.LastChapterIndex, Description = e.Description, IsReadyForReading = e.IsReadyForReading }).FirstOrDefault(), RecentQuizzes = u.QuizResults.OrderByDescending(q => q.CompletedDate).Take(5).Select(q => new QuizResultDto { Id = q.Id, Topic = q.Topic, Score = q.Score, TotalQuestions = q.TotalQuestions, Percentage = q.Percentage, CompletedDate = q.CompletedDate }).ToList(), MappedConcepts = dbContext.KnowledgeUnits .Where(k => k.TenantId == u.TenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId)) .OrderByDescending(k => k.CreatedAt) .Take(6) .Select(k => new MappedConceptDto { Id = k.Id, Type = k.Type.ToString(), Content = k.Content }) .ToList(), Roles = dbContext.UserRoles .Where(ur => ur.UserId == u.Id) .Join(dbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name!) .ToArray() }) .FirstOrDefaultAsync(cancellationToken); if (profile == null) { return Result.Fail("Profile not found."); } return Result.Ok(profile); } }