package org.fuseri.modulecertificate.certificate;

import io.swagger.v3.oas.annotations.Operation;
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.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.fuseri.model.dto.certificate.CertificateCreateDto;
import org.fuseri.model.dto.certificate.CertificateSimpleDto;
import org.fuseri.modulecertificate.ModuleCertificateApplication;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.List;

/**
 * This class represents a RESTful controller for Certificate module.
 * It handles incoming HTTP requests for generating and retrieving course certificates,
 * and delegates them to the appropriate service method.
 */
@RestController
@RequestMapping("/certificates")
public class CertificateController {

    private final CertificateFacade certificateFacade;

    @Autowired
    public CertificateController(CertificateFacade certificateFacade) {
        this.certificateFacade = certificateFacade;
    }


    /**
     * Generates certificate for specified user and course.
     *
     * @param certificateCreateDto Dto with data used for generating certificate
     * @return certificate file
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Generate certificate",
            description = "Generates certificate, saves it into database and returns certificate file.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "Certificate generated successfully."),
            @ApiResponse(responseCode = "500", description = "Internal server error.")
    })
    @PostMapping
    public ResponseEntity<Void> generate(@Valid @RequestBody CertificateCreateDto certificateCreateDto, HttpServletResponse response) throws IOException {
        certificateFacade.generate(certificateCreateDto, response);
        return ResponseEntity.ok().build();
    }

    /**
     * Retrieves previously generated certificate.
     *
     * @param id ID of certificate to be retrieved
     * @return CertificateDto with data of previously generated certificate with specified ID
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Get a certificate by ID", description = "Returns a certificate with the specified ID.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Certificate with the specified ID retrieved successfully."),
            @ApiResponse(responseCode = "404", description = "Certificate with the specified ID was not found."),
            @ApiResponse(responseCode = "400", description = "Invalid input.")
    })
    @GetMapping("/{id}")
    public ResponseEntity<CertificateSimpleDto> find(@NotNull @PathVariable  Long id) {
            return ResponseEntity.ok(certificateFacade.findById(id));
    }

    /**
     * Retrieves previously generated certificates for user.
     *
     * @param userId ID of user to retrieve certificates for.
     * @return List of CertificateDto objects with previously generated certificates
     * for specified User.
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Get certificates for user", description = "Returns certificates for given user in list.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Successfully retrieved certificates"),
            @ApiResponse(responseCode = "500", description = "Internal server error."),
    })
    @GetMapping("/find-for-user")
    public ResponseEntity<List<CertificateSimpleDto>> findForUser(@RequestParam Long userId) {
        return ResponseEntity.ok(certificateFacade.findByUserId(userId));
    }

    /**
     * Retrieves previously generated certificate ID.
     *
     * @param userId   ID of user to retrieve certificates for.
     * @param courseId ID of course to retrieve certificates for.
     * @return List of CertificateDto objects with previously generated certificates
     * for specified User and Course.
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Get certificates for user and course",
            description = "Returns certificates for given user and course in list.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Successfully retrieved certificates"),
            @ApiResponse(responseCode = "500", description = "Internal server error."),
            @ApiResponse(responseCode = "400", description = "Invalid input."),
    })
    @GetMapping("/find-for-user-and-course")
    public ResponseEntity<List<CertificateSimpleDto>> findForUserAndCourse(@RequestParam Long userId, @RequestParam Long courseId) {
        return  ResponseEntity.ok(certificateFacade.findByUserIdAndCourseId(userId, courseId));
    }

    /**
     * Retrieves previously generated certificate ID.
     *
     * @param id Id of certificate to be deleted.
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Delete a certificate with specified ID", description = "Deletes a certificate with the specified ID.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "Certificate with the specified ID deleted successfully."),
            @ApiResponse(responseCode = "500", description = "Internal server error."),
            @ApiResponse(responseCode = "400", description = "Invalid input.")
    })
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@NotNull @PathVariable Long id) {
        certificateFacade.deleteCertificate(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * Find certificates and return them in a paginated format
     *
     * @return a Result object containing a list of CertificateDto objects and pagination information
     */
    @Operation(security = @SecurityRequirement(name = ModuleCertificateApplication.SECURITY_SCHEME_NAME),
            summary = "Get certificates in paginated format", description = "Returns certificates in paginated format.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Successfully retrieved paginated certificates"),
            @ApiResponse(responseCode = "500", description = "Internal server error.")
    })
    @GetMapping
    public ResponseEntity<Page<CertificateSimpleDto>> findAllCertificates(@ParameterObject Pageable pageable) {
        return ResponseEntity.ok(certificateFacade.findAll(pageable));
    }
}
