using GermanApp.Application.DTOs;
using GermanApp.Application.Interfaces;
using GermanApp.Application.DTOs.Auth;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace GermanApp.Presentation.Controllers;
///
/// API controller for admin operations.
/// All endpoints require Admin role.
/// This is part of the Presentation layer.
///
[ApiController]
[Route("api/[controller]")]
[Authorize(Roles = "Admin")]
public class AdminController : ControllerBase
{
private readonly IAdminService _adminService;
private readonly IUserReportService _reportService;
public AdminController(IAdminService adminService, IUserReportService reportService)
{
_adminService = adminService;
_reportService = reportService;
}
// ============================================
// USER MANAGEMENT ENDPOINTS
// ============================================
///
/// Gets all users (Admin only).
///
/// Cancellation token
/// List of all users
[HttpGet("users")]
[ProducesResponseType(typeof(IReadOnlyList), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetAllUsersAsync(CancellationToken cancellationToken = default)
{
var users = await _adminService.GetAllUsersAsync(cancellationToken);
return Ok(users);
}
///
/// Gets a specific user by ID (Admin only).
///
/// The user ID
/// Cancellation token
/// The user DTO
[HttpGet("users/{userId}")]
[ProducesResponseType(typeof(AdminUserDto), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetUserByIdAsync(int userId, CancellationToken cancellationToken = default)
{
var user = await _adminService.GetUserByIdAsync(userId, cancellationToken);
if (user == null)
return NotFound();
return Ok(user);
}
///
/// Updates a user's role (Admin only).
///
/// The user ID
/// The role update data
/// Cancellation token
/// The updated user DTO
[HttpPut("users/{userId}/role")]
[ProducesResponseType(typeof(AdminUserDto), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task UpdateUserRoleAsync(
int userId,
[FromBody] UpdateUserRoleDto dto,
CancellationToken cancellationToken = default)
{
try
{
var user = await _adminService.UpdateUserRoleAsync(userId, dto.Role, cancellationToken);
if (user == null)
return NotFound();
return Ok(user);
}
catch (ArgumentException ex)
{
return BadRequest(ex.Message);
}
}
///
/// Deletes a user (Admin only, cannot delete self).
///
/// The user ID to delete
/// Cancellation token
/// Success or error
[HttpDelete("users/{userId}")]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task DeleteUserAsync(int userId, CancellationToken cancellationToken = default)
{
try
{
var adminUserId = int.Parse(User.FindFirst("nameid")?.Value ?? "0");
var result = await _adminService.DeleteUserAsync(userId, adminUserId, cancellationToken);
if (!result)
return NotFound();
return NoContent();
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}
// ============================================
// DASHBOARD ENDPOINTS
// ============================================
///
/// Gets admin dashboard statistics.
///
/// Cancellation token
/// Dashboard statistics
[HttpGet("dashboard/stats")]
[ProducesResponseType(typeof(AdminDashboardStatsDto), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetDashboardStatsAsync(CancellationToken cancellationToken = default)
{
var stats = await _adminService.GetDashboardStatsAsync(cancellationToken);
return Ok(stats);
}
// ============================================
// REPORT ENDPOINTS
// ============================================
///
/// Generates a progress report for a specific user.
///
/// The user ID
/// Cancellation token
/// User progress report
[HttpGet("reports/users/{userId}")]
[ProducesResponseType(typeof(UserProgressReportDto), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetUserReportAsync(int userId, CancellationToken cancellationToken = default)
{
try
{
var report = await _reportService.GenerateUserReportAsync(userId, cancellationToken);
return Ok(report);
}
catch (ArgumentException ex)
{
return BadRequest(ex.Message);
}
}
///
/// Generates progress reports for all users.
///
/// Cancellation token
/// List of all user progress reports
[HttpGet("reports/all-users")]
[ProducesResponseType(typeof(IReadOnlyList), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetAllUserReportsAsync(CancellationToken cancellationToken = default)
{
var reports = await _reportService.GenerateAllUserReportsAsync(cancellationToken);
return Ok(reports);
}
///
/// Gets lesson completion data for a user.
///
/// The user ID
/// Cancellation token
/// List of lesson completion data
[HttpGet("reports/users/{userId}/lessons")]
[ProducesResponseType(typeof(IReadOnlyList), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetUserLessonProgressAsync(int userId, CancellationToken cancellationToken = default)
{
var progress = await _reportService.GetUserLessonProgressAsync(userId, cancellationToken);
return Ok(progress);
}
///
/// Gets quiz results for a user.
///
/// The user ID
/// Cancellation token
/// List of quiz results
[HttpGet("reports/users/{userId}/quizzes")]
[ProducesResponseType(typeof(IReadOnlyList), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetUserQuizResultsAsync(int userId, CancellationToken cancellationToken = default)
{
var results = await _reportService.GetUserQuizResultsAsync(userId, cancellationToken);
return Ok(results);
}
///
/// Exports all user reports as CSV.
///
/// Cancellation token
/// CSV content
[HttpGet("reports/export/csv")]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task ExportReportsAsCsvAsync(CancellationToken cancellationToken = default)
{
var csv = await _reportService.ExportReportsAsCsvAsync(cancellationToken);
return Ok(new { CsvContent = csv });
}
///
/// Gets a specific user's full report (combined data).
///
/// The user ID
/// Cancellation token
/// Combined user report data
[HttpGet("reports/users/{userId}/full")]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetUserFullReportAsync(int userId, CancellationToken cancellationToken = default)
{
try
{
var progressReportTask = _reportService.GenerateUserReportAsync(userId, cancellationToken);
var lessonProgressTask = _reportService.GetUserLessonProgressAsync(userId, cancellationToken);
var quizResultsTask = _reportService.GetUserQuizResultsAsync(userId, cancellationToken);
await Task.WhenAll(progressReportTask, lessonProgressTask, quizResultsTask);
return Ok(new
{
ProgressReport = await progressReportTask,
LessonProgress = await lessonProgressTask,
QuizResults = await quizResultsTask
});
}
catch (ArgumentException ex)
{
return BadRequest(ex.Message);
}
}
}