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);
}
}