package com.lions.dev.resource; import com.lions.dev.dto.request.establishment.EstablishmentRatingRequestDTO; import com.lions.dev.dto.response.establishment.EstablishmentRatingResponseDTO; import com.lions.dev.dto.response.establishment.EstablishmentRatingStatsResponseDTO; import com.lions.dev.entity.establishment.EstablishmentRating; import com.lions.dev.service.EstablishmentRatingService; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; import java.util.Map; import java.util.UUID; /** * Ressource REST pour la gestion des notations d'établissements. * Cette classe expose des endpoints pour soumettre, modifier et récupérer les notes. */ @Path("/establishments/{establishmentId}/ratings") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Tag(name = "Establishment Ratings", description = "Opérations liées aux notations des établissements") public class EstablishmentRatingResource { @Inject EstablishmentRatingService ratingService; private static final Logger LOG = Logger.getLogger(EstablishmentRatingResource.class); /** * Soumet une nouvelle note pour un établissement. */ @POST @Transactional @Operation(summary = "Soumettre une note pour un établissement", description = "Soumet une nouvelle note (1 à 5 étoiles) pour un établissement") public Response submitRating( @PathParam("establishmentId") String establishmentId, @QueryParam("userId") String userIdStr, @Valid EstablishmentRatingRequestDTO requestDTO) { LOG.info("Soumission d'une note pour l'établissement " + establishmentId + " par l'utilisateur " + userIdStr); try { UUID id = UUID.fromString(establishmentId); UUID userId = UUID.fromString(userIdStr); EstablishmentRating rating = ratingService.submitRating(id, userId, requestDTO); EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } catch (IllegalArgumentException e) { LOG.error("ID invalide : " + e.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity("ID invalide : " + e.getMessage()) .build(); } catch (RuntimeException e) { LOG.error("Erreur lors de la soumission de la note : " + e.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity(e.getMessage()) .build(); } catch (Exception e) { LOG.error("Erreur inattendue lors de la soumission de la note", e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Erreur lors de la soumission de la note") .build(); } } /** * Met à jour une note existante. */ @PUT @Transactional @Operation(summary = "Modifier une note existante", description = "Met à jour une note existante pour un établissement") public Response updateRating( @PathParam("establishmentId") String establishmentId, @QueryParam("userId") String userIdStr, @Valid EstablishmentRatingRequestDTO requestDTO) { LOG.info("Mise à jour de la note pour l'établissement " + establishmentId + " par l'utilisateur " + userIdStr); try { UUID id = UUID.fromString(establishmentId); UUID userId = UUID.fromString(userIdStr); EstablishmentRating rating = ratingService.updateRating(id, userId, requestDTO); EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); return Response.ok(responseDTO).build(); } catch (IllegalArgumentException e) { LOG.error("ID invalide : " + e.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity("ID invalide : " + e.getMessage()) .build(); } catch (RuntimeException e) { LOG.error("Erreur lors de la mise à jour de la note : " + e.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity(e.getMessage()) .build(); } catch (Exception e) { LOG.error("Erreur inattendue lors de la mise à jour de la note", e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Erreur lors de la mise à jour de la note") .build(); } } /** * Récupère les statistiques de notation d'un établissement. * Doit être déclaré avant les endpoints génériques GET pour la résolution correcte par JAX-RS. */ @GET @Path("/stats") @Operation(summary = "Récupérer les statistiques de notation", description = "Récupère les statistiques de notation d'un établissement (moyenne, total, distribution)") public Response getRatingStats(@PathParam("establishmentId") String establishmentId) { LOG.info("Récupération des statistiques de notation pour l'établissement " + establishmentId); try { UUID id = UUID.fromString(establishmentId); Map stats = ratingService.getRatingStats(id); EstablishmentRatingStatsResponseDTO responseDTO = new EstablishmentRatingStatsResponseDTO( (Double) stats.get("averageRating"), (Integer) stats.get("totalRatingsCount"), (Map) stats.get("ratingDistribution") ); return Response.ok(responseDTO).build(); } catch (IllegalArgumentException e) { LOG.error("ID invalide : " + e.getMessage()); return Response.status(Response.Status.BAD_REQUEST) .entity("ID invalide : " + e.getMessage()) .build(); } catch (Exception e) { LOG.error("Erreur inattendue lors de la récupération des statistiques", e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Erreur lors de la récupération des statistiques") .build(); } } /** * Récupère la note d'un utilisateur pour un établissement (via path parameter). * Endpoint alternatif pour compatibilité. */ @GET @Path("/users/{userId}") @Operation(summary = "Récupérer la note d'un utilisateur (path parameter)", description = "Récupère la note donnée par un utilisateur spécifique pour un établissement (via path parameter)") public Response getUserRatingByPath( @PathParam("establishmentId") String establishmentId, @PathParam("userId") String userIdStr) { LOG.info("Récupération de la note de l'utilisateur " + userIdStr + " pour l'établissement " + establishmentId); try { UUID id = UUID.fromString(establishmentId); UUID userId = UUID.fromString(userIdStr); EstablishmentRating rating = ratingService.getUserRating(id, userId); if (rating == null) { return Response.status(Response.Status.NOT_FOUND) .entity("Note non trouvée") .build(); } EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); return Response.ok(responseDTO).build(); } catch (IllegalArgumentException e) { LOG.error("ID invalide : " + e.getMessage(), e); return Response.status(Response.Status.BAD_REQUEST) .entity("ID invalide : " + e.getMessage()) .build(); } catch (Exception e) { LOG.error("Erreur inattendue lors de la récupération de la note", e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Erreur lors de la récupération de la note") .build(); } } /** * Récupère la note d'un utilisateur pour un établissement (via query parameter). * Endpoint utilisé par le frontend Flutter. * Doit être déclaré en dernier car c'est l'endpoint le plus générique. */ @GET @Operation(summary = "Récupérer la note d'un utilisateur", description = "Récupère la note donnée par un utilisateur spécifique pour un établissement (via query parameter userId)") public Response getUserRatingByQuery( @PathParam("establishmentId") String establishmentId, @QueryParam("userId") String userIdStr) { LOG.info("Récupération de la note de l'utilisateur " + userIdStr + " pour l'établissement " + establishmentId); // Si userId n'est pas fourni, retourner une erreur if (userIdStr == null || userIdStr.isEmpty()) { LOG.warn("userId manquant dans la requête"); return Response.status(Response.Status.BAD_REQUEST) .entity("Le paramètre userId est requis") .build(); } try { UUID id = UUID.fromString(establishmentId); UUID userId = UUID.fromString(userIdStr); EstablishmentRating rating = ratingService.getUserRating(id, userId); if (rating == null) { // Retourner 404 si la note n'existe pas return Response.status(Response.Status.NOT_FOUND) .entity("Note non trouvée") .build(); } EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); return Response.ok(responseDTO).build(); } catch (IllegalArgumentException e) { LOG.error("ID invalide : " + e.getMessage(), e); return Response.status(Response.Status.BAD_REQUEST) .entity("ID invalide : " + e.getMessage()) .build(); } catch (Exception e) { LOG.error("Erreur inattendue lors de la récupération de la note", e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Erreur lors de la récupération de la note") .build(); } } }