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 dev.lions.unionflow.server.service.AlerteLcbFtService;
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;

    @Inject
    AlerteLcbFtService alerteLcbFtService;

    /**
     * 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<AlerteLcbFt> alertes = alerteLcbFtRepository.search(
                orgId,
                typeAlerte,
                traitee,
                debut,
                fin,
                page,
                size
        );

        long total = alerteLcbFtRepository.count(orgId, typeAlerte, traitee, debut, fin);

        List<AlerteLcbFtResponse> responses = alertes.stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());

        Map<String, Object> 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<String, String> body
    ) {
        UUID traiteParId = null;
        String traiteParStr = body.get("traitePar");
        if (traiteParStr != null && !traiteParStr.isBlank()) {
            try {
                traiteParId = UUID.fromString(traiteParStr);
            } catch (IllegalArgumentException e) {
                throw new BadRequestException("traitePar doit être un UUID valide");
            }
        }

        AlerteLcbFt alerte = alerteLcbFtService.traiterAlerte(
                UUID.fromString(id), traiteParId, body.get("commentaire"));
        if (alerte == null) {
            throw new NotFoundException("Alerte non trouvée");
        }
        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();
    }
}
