using GermanApp.Application.DTOs; using GermanApp.Application.Services; using GermanApp.Domain.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace GermanApp.Presentation.Controllers; /// /// API controller for managing quiz questions. /// This is part of the Presentation layer. /// [ApiController] [Route("api/[controller]")] [Authorize] public class QuizQuestionsController : ControllerBase { private readonly QuizQuestionService _quizQuestionService; public QuizQuestionsController(QuizQuestionService quizQuestionService) { _quizQuestionService = quizQuestionService; } /// /// Gets all quiz questions. /// /// List of all quiz questions [HttpGet] [AllowAnonymous] public async Task GetAllQuizQuestionsAsync(CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetAllQuizQuestionsAsync(cancellationToken); return Ok(questions); } /// /// Gets all active quiz questions for a specific quiz. /// /// The quiz ID /// List of quiz questions for the specified quiz [HttpGet("by-quiz/{quizId}")] [AllowAnonymous] public async Task GetQuizQuestionsByQuizAsync(int quizId, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetActiveQuizQuestionsByQuizAsync(quizId, cancellationToken); return Ok(questions); } /// /// Gets all active quiz questions for a specific lesson (legacy - uses first quiz). /// /// The lesson ID /// List of quiz questions for the specified lesson [HttpGet("by-lesson/{lessonId}")] [AllowAnonymous] public async Task GetQuizQuestionsByLessonAsync(int lessonId, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetActiveQuizQuestionsByLessonAsync(lessonId, cancellationToken); return Ok(questions); } /// /// Gets a specific quiz question by its ID. /// /// The quiz question ID /// The quiz question with the specified ID [HttpGet("{id}")] [AllowAnonymous] public async Task GetQuizQuestionByIdAsync(int id, CancellationToken cancellationToken = default) { var question = await _quizQuestionService.GetQuizQuestionByIdAsync(id, cancellationToken); if (question == null) return NotFound(); return Ok(question); } /// /// Gets a random set of quiz questions for a quiz. /// /// The quiz ID /// Number of questions to return /// List of random quiz questions for the quiz [HttpGet("random/{quizId}/{count}")] [AllowAnonymous] public async Task GetRandomQuizQuestionsForQuizAsync(int quizId, int count, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetRandomQuizQuestionsForQuizAsync(quizId, count, cancellationToken); return Ok(questions); } /// /// Gets a random set of quiz questions for a lesson (legacy - uses first quiz). /// /// The lesson ID /// Number of questions to return /// List of random quiz questions for the lesson [HttpGet("random/by-lesson/{lessonId}/{count}")] [AllowAnonymous] public async Task GetRandomQuizQuestionsForLessonAsync(int lessonId, int count, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetRandomQuizQuestionsForLessonAsync(lessonId, count, cancellationToken); return Ok(questions); } /// /// Gets quiz questions by difficulty level. /// /// The difficulty level (1-5) /// List of quiz questions with the specified difficulty [HttpGet("by-difficulty/{difficulty}")] [AllowAnonymous] public async Task GetQuizQuestionsByDifficultyAsync(int difficulty, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetQuizQuestionsByDifficultyAsync(difficulty, cancellationToken); return Ok(questions); } /// /// Gets quiz questions by type. /// /// The question type /// List of quiz questions with the specified type [HttpGet("by-type/{type}")] [AllowAnonymous] public async Task GetQuizQuestionsByTypeAsync(QuestionType type, CancellationToken cancellationToken = default) { var questions = await _quizQuestionService.GetQuizQuestionsByTypeAsync(type, cancellationToken); return Ok(questions); } /// /// Creates a new quiz question. /// /// The quiz question data (requires QuizId) /// The created quiz question [HttpPost] [Authorize(Roles = "Admin")] public async Task CreateQuizQuestionAsync(CreateQuizQuestionDto dto, CancellationToken cancellationToken = default) { var question = await _quizQuestionService.CreateQuizQuestionAsync(dto, cancellationToken); return CreatedAtAction(nameof(GetQuizQuestionByIdAsync), new { id = question.Id }, question); } /// /// Updates an existing quiz question. /// /// The quiz question ID /// The updated quiz question data /// The updated quiz question [HttpPut("{id}")] [Authorize(Roles = "Admin")] public async Task UpdateQuizQuestionAsync(int id, UpdateQuizQuestionDto dto, CancellationToken cancellationToken = default) { var question = await _quizQuestionService.UpdateQuizQuestionAsync(id, dto, cancellationToken); if (question == null) return NotFound(); return Ok(question); } /// /// Deletes a quiz question by its ID. /// /// The quiz question ID /// No content on success [HttpDelete("{id}")] [Authorize(Roles = "Admin")] public async Task DeleteQuizQuestionAsync(int id, CancellationToken cancellationToken = default) { var result = await _quizQuestionService.DeleteQuizQuestionAsync(id, cancellationToken); if (!result) return NotFound(); return NoContent(); } /// /// Gets quiz options for a specific question. /// /// The question ID /// List of quiz options for the question [HttpGet("options/{questionId}")] [AllowAnonymous] public async Task GetQuizOptionsByQuestionAsync(int questionId, CancellationToken cancellationToken = default) { var options = await _quizQuestionService.GetQuizOptionsByQuestionAsync(questionId, cancellationToken); return Ok(options); } /// /// Gets the correct option for a question. /// /// The question ID /// The correct option for the question [HttpGet("correct-option/{questionId}")] [AllowAnonymous] public async Task GetCorrectOptionAsync(int questionId, CancellationToken cancellationToken = default) { var option = await _quizQuestionService.GetCorrectOptionAsync(questionId, cancellationToken); if (option == null) return NotFound(); return Ok(option); } /// /// Gets all correct options for a question (for MultipleSelect type). /// /// The question ID /// List of correct options for the question [HttpGet("correct-options/{questionId}")] [AllowAnonymous] public async Task GetCorrectOptionsAsync(int questionId, CancellationToken cancellationToken = default) { var options = await _quizQuestionService.GetCorrectOptionsAsync(questionId, cancellationToken); return Ok(options); } /// /// Creates a new quiz option for a question. /// /// The question ID /// The quiz option data /// The created quiz option [HttpPost("options/{questionId}")] [Authorize(Roles = "Admin")] public async Task CreateQuizOptionAsync(int questionId, CreateQuizOptionDto dto, CancellationToken cancellationToken = default) { var option = await _quizQuestionService.CreateQuizOptionAsync(questionId, dto, cancellationToken); return CreatedAtAction(nameof(GetQuizOptionsByQuestionAsync), new { questionId }, option); } /// /// Updates an existing quiz option. /// /// The quiz option ID /// The updated quiz option data /// The updated quiz option [HttpPut("options/{id}")] [Authorize(Roles = "Admin")] public async Task UpdateQuizOptionAsync(int id, UpdateQuizOptionDto dto, CancellationToken cancellationToken = default) { var option = await _quizQuestionService.UpdateQuizOptionAsync(id, dto, cancellationToken); if (option == null) return NotFound(); return Ok(option); } /// /// Deletes a quiz option by its ID. /// /// The quiz option ID /// No content on success [HttpDelete("options/{id}")] [Authorize(Roles = "Admin")] public async Task DeleteQuizOptionAsync(int id, CancellationToken cancellationToken = default) { var result = await _quizQuestionService.DeleteQuizOptionAsync(id, cancellationToken); if (!result) return NotFound(); return NoContent(); } /// /// Submits quiz answers and returns the result. /// /// The user ID /// The quiz answers submission (requires QuizId) /// The quiz result [HttpPost("submit/{userId}")] [Authorize] public async Task SubmitQuizAnswersAsync(int userId, SubmitQuizAnswersDto dto, CancellationToken cancellationToken = default) { // Convert legacy DTO to new format var newDto = new SubmitQuizDto(dto.QuizId, dto.Answers); var result = await _quizQuestionService.SubmitQuizAnswersForQuizAsync(userId, newDto, cancellationToken); return Ok(result); } /// /// Gets the number of quiz questions for a lesson. /// /// The lesson ID /// The count of quiz questions for the lesson [HttpGet("count/{lessonId}")] [AllowAnonymous] public async Task GetQuizQuestionCountForLessonAsync(int lessonId, CancellationToken cancellationToken = default) { var count = await _quizQuestionService.GetQuizQuestionCountForLessonAsync(lessonId, cancellationToken); return Ok(new { lessonId, count }); } /// /// Gets the difficulty distribution for a lesson. /// /// The lesson ID /// The difficulty distribution for the lesson [HttpGet("difficulty-distribution/{lessonId}")] [AllowAnonymous] public async Task GetDifficultyDistributionAsync(int lessonId, CancellationToken cancellationToken = default) { var distribution = await _quizQuestionService.GetDifficultyDistributionAsync(lessonId, cancellationToken); return Ok(distribution); } /// /// Gets the type distribution for a lesson. /// /// The lesson ID /// The type distribution for the lesson [HttpGet("type-distribution/{lessonId}")] [AllowAnonymous] public async Task GetTypeDistributionAsync(int lessonId, CancellationToken cancellationToken = default) { var distribution = await _quizQuestionService.GetTypeDistributionAsync(lessonId, cancellationToken); return Ok(distribution); } }