using GermanApp.Application.DTOs; using GermanApp.Application.Interfaces; using GermanApp.Domain.Entities; using GermanApp.Domain.Interfaces; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace GermanApp.Application.Services; /// /// Service for admin operations. /// Part of the Application layer. /// public class AdminService : IAdminService { private readonly IRepository _userRepository; private readonly ILevelRepository _levelRepository; private readonly ILessonRepository _lessonRepository; private readonly IQuizRepository _quizRepository; private readonly IStoryRepository _storyRepository; private readonly IUserProgressRepository _userProgressRepository; public AdminService( IRepository userRepository, ILevelRepository levelRepository, ILessonRepository lessonRepository, IQuizRepository quizRepository, IStoryRepository storyRepository, IUserProgressRepository userProgressRepository) { _userRepository = userRepository; _levelRepository = levelRepository; _lessonRepository = lessonRepository; _quizRepository = quizRepository; _storyRepository = storyRepository; _userProgressRepository = userProgressRepository; } /// /// Gets all users for admin view. /// /// Cancellation token /// List of all users public async Task> GetAllUsersAsync(CancellationToken cancellationToken = default) { var users = await _userRepository.GetAllAsync(cancellationToken); return users.Select(u => new AdminUserListItemDto( u.Id, u.Username, u.Email, u.Role, u.CurrentLevel, u.TotalPoints, u.Streak, u.CreatedAt)) .OrderBy(u => u.Username) .ToList(); } /// /// Gets a specific user by ID. /// /// The user ID /// Cancellation token /// The user DTO public async Task GetUserByIdAsync(int userId, CancellationToken cancellationToken = default) { var user = await _userRepository.GetByIdAsync(userId, cancellationToken); if (user == null) return null; return new AdminUserDto( user.Id, user.Username, user.Email, user.Role, user.CurrentLevel, user.Streak, user.TotalPoints, user.CreatedAt); } /// /// Updates a user's role. /// /// The user ID /// The new role /// Cancellation token /// The updated user DTO public async Task UpdateUserRoleAsync(int userId, string newRole, CancellationToken cancellationToken = default) { var user = await _userRepository.GetByIdAsync(userId, cancellationToken); if (user == null) return null; // Validate role and update using domain method user.SetRole(newRole); await _userRepository.UpdateAsync(user, cancellationToken); return new AdminUserDto( user.Id, user.Username, user.Email, user.Role, user.CurrentLevel, user.Streak, user.TotalPoints, user.CreatedAt); } /// /// Deletes a user (admin only, cannot delete self). /// /// The user ID to delete /// The admin user ID making the request /// Cancellation token /// True if successful public async Task DeleteUserAsync(int userId, int adminUserId, CancellationToken cancellationToken = default) { // Cannot delete self if (userId == adminUserId) throw new InvalidOperationException("Cannot delete your own user account."); // Check if user exists var user = await _userRepository.GetByIdAsync(userId, cancellationToken); if (user == null) return false; // Prevent deleting the last admin var allUsers = await _userRepository.GetAllAsync(cancellationToken); var adminCount = allUsers.Count(u => u.IsAdmin()); if (user.IsAdmin() && adminCount <= 1) throw new InvalidOperationException("Cannot delete the last admin user."); await _userRepository.DeleteAsync(user, cancellationToken); return true; } /// /// Gets admin dashboard statistics. /// /// Cancellation token /// Dashboard statistics public async Task GetDashboardStatsAsync(CancellationToken cancellationToken = default) { var usersTask = _userRepository.GetAllAsync(cancellationToken); var lessonsTask = _lessonRepository.GetAllAsync(cancellationToken); var quizzesTask = _quizRepository.GetAllAsync(cancellationToken); var userProgressTask = _userProgressRepository.GetAllAsync(cancellationToken); await Task.WhenAll(usersTask, lessonsTask, quizzesTask, userProgressTask); var users = await usersTask; var lessons = await lessonsTask; var quizzes = await quizzesTask; var userProgress = await userProgressTask; // Get all levels and count story segments var levels = await _levelRepository.GetAllAsync(cancellationToken); var storyCount = 0; foreach (var level in levels) { var segments = await _storyRepository.GetByLevelAsync(level.Id, true, cancellationToken); storyCount += segments.Count; } // Calculate active users this week var oneWeekAgo = DateTime.UtcNow.AddDays(-7); var activeUsersThisWeek = userProgress .Where(up => up.LastAttemptDate >= oneWeekAgo) .Select(up => up.UserId) .Distinct() .Count(); // Calculate average user progress var completedLessons = userProgress.Count(up => up.IsCompleted); var totalPossibleProgress = users.Count * lessons.Count; var averageProgress = totalPossibleProgress > 0 ? (double)completedLessons / totalPossibleProgress * 100 : 0; return new AdminDashboardStatsDto( users.Count, lessons.Count, quizzes.Count, storyCount, activeUsersThisWeek, averageProgress); } }