package org.fuseri.moduleexercise.question;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.fuseri.model.dto.exercise.AnswerDto;
import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto;
import org.fuseri.model.dto.exercise.QuestionCreateDto;
import org.fuseri.model.dto.exercise.QuestionDto;
import org.fuseri.model.dto.exercise.QuestionUpdateDto;
import org.fuseri.moduleexercise.ModuleExerciseApplication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * Represent a REST API controller for questions
 * Handle HTTP requests related to questions
 */
@RestController
@RequestMapping("/questions")
public class QuestionController {

    private final QuestionFacade questionFacade;

    /**
     * Constructor for QuestionController
     *
     * @param questionFacade the service responsible for handling question-related logic
     */
    @Autowired
    public QuestionController(QuestionFacade questionFacade) {
        this.questionFacade = questionFacade;
    }

    /**
     * Find a question by ID.
     *
     * @param id the ID of the question to find
     * @return a ResponseEntity containing a QuestionDto object representing the found question, or a 404 Not Found response
     * if the question with the specified ID was not found
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Get a question by ID", description = "Returns a question with the specified ID.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Question with the specified ID retrieved successfully.",
                    content = @Content(schema = @Schema(implementation = QuestionDto.class))),
            @ApiResponse(responseCode = "404", description = "Question with the specified ID was not found.")
    })
    @GetMapping("/{id}")
    public ResponseEntity<QuestionDto> find(@NotNull @PathVariable long id) {
        return ResponseEntity.ok(questionFacade.find(id));
    }

    /**
     * Retrieve a list of AnswerDto objects which belong to the question with ID
     *
     * @param id the ID of the question for which to retrieve answers
     * @return a ResponseEntity containing a List of AnswerDto objects, or a 404 Not Found response
     * if the question with the specified ID was not found
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Retrieve answers for a specific question")
    @ApiResponse(responseCode = "200", description = "Successfully retrieved answers",
            content = @Content(schema = @Schema(implementation = AnswerDto.class)))
    @ApiResponse(responseCode = "404", description = "Question not found")
    @GetMapping("/{id}/answers")
    public ResponseEntity<List<AnswerDto>> getQuestionAnswers(@NotNull @PathVariable long id) {
        return ResponseEntity.ok(questionFacade.getQuestionAnswers(id));
    }

    /**
     * Add a new question to an exercise
     *
     * @param dto a QuestionCreateDto object representing the new question to add
     * @return a ResponseEntity containing a QuestionDto object representing the posted question, or a 404 Not Found response
     * if the exercise with the specified ID in dto was not found
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Add a new question with answers to an exercise",
            description = "Creates a new question with answers and associates it with the specified exercise.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "Question with answers created and added to the exercise successfully.",
                    content = @Content(schema = @Schema(implementation = QuestionDto.class))),
            @ApiResponse(responseCode = "404", description = "Exercise with the specified ID was not found.")
    })
    @PostMapping
    public ResponseEntity<QuestionDto> createQuestion(@Valid @RequestBody QuestionCreateDto dto) {
        QuestionDto createdQuestionDto = questionFacade.create(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdQuestionDto);
    }

    /**
     * Update question
     *
     * @param dto a QuestionDto object representing the updated question with correct id
     * @return a ResponseEntity containing a QuestionUpdateDto object representing the updated question,
     * or a 404 Not Found response if the question with the specified ID was not found
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Update a question by ID", description = "Updates a question with the specified ID.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Question with the specified ID updated successfully."),
            @ApiResponse(responseCode = "404", description = "Question with the specified ID was not found.")
    })
    @PutMapping("/{id}")
    public ResponseEntity<QuestionDto> updateQuestion(@NotNull @PathVariable long id, @Valid @RequestBody QuestionUpdateDto dto) {
        return ResponseEntity.ok(questionFacade.patchUpdate(id, dto));
    }

    /**
     * Delete question with ID from exercise
     *
     * @param id of question to delete
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Delete a question with specified ID", description = "Deletes a question with the specified ID.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "Question with the specified ID deleted successfully."),
    })
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteQuestion(@NotNull @PathVariable long id) {
        questionFacade.delete(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * Adds answers to the existing question resource
     *
     * @param id id of question to update
     * @return the LectureDto representing the updated lecture
     */
    @Operation(security = @SecurityRequirement(name = ModuleExerciseApplication.SECURITY_SCHEME_NAME),
            summary = "Add answers to the existing question.")
    @PatchMapping("/{id}/answers")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "The question has been successfully updated"),
            @ApiResponse(responseCode = "400", description = "The request body is invalid"),
            @ApiResponse(responseCode = "404", description = "The question with the specified ID does not exist")
    })
    public ResponseEntity<QuestionDto> addAnswers(@PathVariable Long id, @RequestBody List<AnswerInQuestionCreateDto> answerDtoList) {
        return ResponseEntity.ok(questionFacade.addAnswers(id, answerDtoList));
    }
}