package dev.lions.unionflow.server.resource; import dev.lions.unionflow.server.api.dto.lcbft.AlerteLcbFtResponse; import dev.lions.unionflow.server.entity.AlerteLcbFt; import dev.lions.unionflow.server.repository.AlerteLcbFtRepository; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; 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 java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; /** * API REST pour la gestion des alertes LCB-FT. * * @author UnionFlow Team * @version 1.0 * @since 2026-03-15 */ @Path("/api/alertes-lcb-ft") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Tag(name = "Alertes LCB-FT", description = "Gestion des alertes Lutte Contre le Blanchiment") public class AlerteLcbFtResource { @Inject AlerteLcbFtRepository alerteLcbFtRepository; /** * Récupère les alertes LCB-FT avec filtres et pagination. */ @GET @RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"}) @Operation(summary = "Liste des alertes LCB-FT", description = "Récupère les alertes avec filtrage et pagination") public Response getAlertes( @QueryParam("organisationId") String organisationId, @QueryParam("typeAlerte") String typeAlerte, @QueryParam("traitee") Boolean traitee, @QueryParam("dateDebut") String dateDebut, @QueryParam("dateFin") String dateFin, @QueryParam("page") @DefaultValue("0") int page, @QueryParam("size") @DefaultValue("20") int size ) { UUID orgId = organisationId != null && !organisationId.isBlank() ? UUID.fromString(organisationId) : null; LocalDateTime debut = dateDebut != null && !dateDebut.isBlank() ? LocalDateTime.parse(dateDebut) : null; LocalDateTime fin = dateFin != null && !dateFin.isBlank() ? LocalDateTime.parse(dateFin) : null; List alertes = alerteLcbFtRepository.search( orgId, typeAlerte, traitee, debut, fin, page, size ); long total = alerteLcbFtRepository.count(orgId, typeAlerte, traitee, debut, fin); List responses = alertes.stream() .map(this::mapToResponse) .collect(Collectors.toList()); Map result = new HashMap<>(); result.put("content", responses); result.put("totalElements", total); result.put("totalPages", (int) Math.ceil((double) total / size)); result.put("currentPage", page); result.put("pageSize", size); return Response.ok(result).build(); } /** * Récupère une alerte par son ID. */ @GET @Path("/{id}") @RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"}) @Operation(summary = "Détails d'une alerte", description = "Récupère une alerte par son ID") public Response getAlerteById(@PathParam("id") String id) { AlerteLcbFt alerte = alerteLcbFtRepository.findById(UUID.fromString(id)); if (alerte == null) { throw new NotFoundException("Alerte non trouvée"); } return Response.ok(mapToResponse(alerte)).build(); } /** * Marque une alerte comme traitée. */ @POST @Path("/{id}/traiter") @RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"}) @Operation(summary = "Traiter une alerte", description = "Marque une alerte comme traitée avec un commentaire") public Response traiterAlerte( @PathParam("id") String id, Map body ) { AlerteLcbFt alerte = alerteLcbFtRepository.findById(UUID.fromString(id)); if (alerte == null) { throw new NotFoundException("Alerte non trouvée"); } alerte.setTraitee(true); alerte.setDateTraitement(LocalDateTime.now()); String traiteParStr = body.get("traitePar"); if (traiteParStr != null && !traiteParStr.isBlank()) { try { alerte.setTraitePar(UUID.fromString(traiteParStr)); } catch (IllegalArgumentException e) { throw new BadRequestException("traitePar doit être un UUID valide"); } } alerte.setCommentaireTraitement(body.get("commentaire")); alerteLcbFtRepository.persist(alerte); return Response.ok(mapToResponse(alerte)).build(); } /** * Compte les alertes non traitées. */ @GET @Path("/stats/non-traitees") @RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"}) @Operation(summary = "Statistiques alertes", description = "Nombre d'alertes non traitées") public Response getStatsNonTraitees(@QueryParam("organisationId") String organisationId) { UUID orgId = organisationId != null && !organisationId.isBlank() ? UUID.fromString(organisationId) : null; long count = alerteLcbFtRepository.countNonTraitees(orgId); return Response.ok(Map.of("count", count)).build(); } private AlerteLcbFtResponse mapToResponse(AlerteLcbFt alerte) { return AlerteLcbFtResponse.builder() .id(alerte.getId().toString()) .organisationId(alerte.getOrganisation() != null ? alerte.getOrganisation().getId().toString() : null) .organisationNom(alerte.getOrganisation() != null ? alerte.getOrganisation().getNom() : null) .membreId(alerte.getMembre() != null ? alerte.getMembre().getId().toString() : null) .membreNomComplet(alerte.getMembre() != null ? alerte.getMembre().getPrenom() + " " + alerte.getMembre().getNom() : null) .typeAlerte(alerte.getTypeAlerte()) .dateAlerte(alerte.getDateAlerte()) .description(alerte.getDescription()) .details(alerte.getDetails()) .montant(alerte.getMontant()) .seuil(alerte.getSeuil()) .typeOperation(alerte.getTypeOperation()) .transactionRef(alerte.getTransactionRef()) .severite(alerte.getSeverite()) .traitee(alerte.getTraitee()) .dateTraitement(alerte.getDateTraitement()) .traitePar(alerte.getTraitePar() != null ? alerte.getTraitePar().toString() : null) .commentaireTraitement(alerte.getCommentaireTraitement()) .build(); } }