package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.api.dto.solidarite.DemandeAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.PropositionAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.EvaluationAideDTO;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.service.SolidariteService;

import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
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.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * Ressource REST pour le système de solidarité UnionFlow
 * 
 * Cette ressource expose les endpoints pour la gestion complète
 * du système de solidarité : demandes, propositions, évaluations.
 * 
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-16
 */
@Path("/api/v1/solidarite")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Solidarité", description = "API de gestion du système de solidarité")
public class SolidariteResource {
    
    private static final Logger LOG = Logger.getLogger(SolidariteResource.class);
    
    @Inject
    SolidariteService solidariteService;
    
    // === ENDPOINTS DEMANDES D'AIDE ===
    
    @POST
    @Path("/demandes")
    @Operation(summary = "Créer une nouvelle demande d'aide", 
               description = "Crée une nouvelle demande d'aide dans le système")
    @APIResponse(responseCode = "201", description = "Demande créée avec succès")
    @APIResponse(responseCode = "400", description = "Données invalides")
    @APIResponse(responseCode = "500", description = "Erreur serveur")
    public Response creerDemandeAide(@Valid DemandeAideDTO demandeDTO) {
        LOG.infof("Création d'une nouvelle demande d'aide: %s", demandeDTO.getTitre());
        
        try {
            DemandeAideDTO demandeCreee = solidariteService.creerDemandeAide(demandeDTO);
            return Response.status(Response.Status.CREATED)
                          .entity(demandeCreee)
                          .build();
                          
        } catch (IllegalArgumentException e) {
            LOG.warnf("Données invalides pour la création de demande: %s", e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                          .entity(Map.of("erreur", e.getMessage()))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la création de demande d'aide");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @GET
    @Path("/demandes/{id}")
    @Operation(summary = "Obtenir une demande d'aide par ID", 
               description = "Récupère les détails d'une demande d'aide spécifique")
    @APIResponse(responseCode = "200", description = "Demande trouvée")
    @APIResponse(responseCode = "404", description = "Demande non trouvée")
    public Response obtenirDemandeAide(@Parameter(description = "ID de la demande") 
                                      @PathParam("id") @NotBlank String id) {
        LOG.debugf("Récupération de la demande d'aide: %s", id);
        
        try {
            DemandeAideDTO demande = solidariteService.obtenirDemandeAide(id);
            
            if (demande == null) {
                return Response.status(Response.Status.NOT_FOUND)
                              .entity(Map.of("erreur", "Demande non trouvée"))
                              .build();
            }
            
            return Response.ok(demande).build();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la récupération de la demande: %s", id);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @PUT
    @Path("/demandes/{id}")
    @Operation(summary = "Mettre à jour une demande d'aide", 
               description = "Met à jour les informations d'une demande d'aide")
    @APIResponse(responseCode = "200", description = "Demande mise à jour")
    @APIResponse(responseCode = "404", description = "Demande non trouvée")
    @APIResponse(responseCode = "400", description = "Données invalides")
    public Response mettreAJourDemandeAide(@PathParam("id") @NotBlank String id,
                                          @Valid DemandeAideDTO demandeDTO) {
        LOG.infof("Mise à jour de la demande d'aide: %s", id);
        
        try {
            demandeDTO.setId(id); // S'assurer que l'ID correspond
            DemandeAideDTO demandeMiseAJour = solidariteService.mettreAJourDemandeAide(demandeDTO);
            
            return Response.ok(demandeMiseAJour).build();
            
        } catch (IllegalArgumentException e) {
            LOG.warnf("Données invalides pour la mise à jour: %s", e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                          .entity(Map.of("erreur", e.getMessage()))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la mise à jour de la demande: %s", id);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @POST
    @Path("/demandes/{id}/soumettre")
    @Operation(summary = "Soumettre une demande d'aide", 
               description = "Soumet une demande d'aide pour évaluation")
    @APIResponse(responseCode = "200", description = "Demande soumise avec succès")
    @APIResponse(responseCode = "404", description = "Demande non trouvée")
    @APIResponse(responseCode = "400", description = "Demande ne peut pas être soumise")
    public Response soumettreDemande(@PathParam("id") @NotBlank String id) {
        LOG.infof("Soumission de la demande d'aide: %s", id);
        
        try {
            DemandeAideDTO demandesoumise = solidariteService.soumettreDemande(id);
            return Response.ok(demandesoumise).build();
            
        } catch (IllegalStateException e) {
            LOG.warnf("Impossible de soumettre la demande %s: %s", id, e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                          .entity(Map.of("erreur", e.getMessage()))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la soumission de la demande: %s", id);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @POST
    @Path("/demandes/{id}/evaluer")
    @Operation(summary = "Évaluer une demande d'aide", 
               description = "Évalue une demande d'aide et prend une décision")
    @APIResponse(responseCode = "200", description = "Demande évaluée avec succès")
    @APIResponse(responseCode = "404", description = "Demande non trouvée")
    @APIResponse(responseCode = "400", description = "Évaluation invalide")
    public Response evaluerDemande(@PathParam("id") @NotBlank String id,
                                  @Valid Map<String, Object> evaluationData) {
        LOG.infof("Évaluation de la demande d'aide: %s", id);
        
        try {
            String evaluateurId = (String) evaluationData.get("evaluateurId");
            StatutAide decision = StatutAide.valueOf((String) evaluationData.get("decision"));
            String commentaire = (String) evaluationData.get("commentaire");
            Double montantApprouve = evaluationData.get("montantApprouve") != null ? 
                                    ((Number) evaluationData.get("montantApprouve")).doubleValue() : null;
            
            DemandeAideDTO demandeEvaluee = solidariteService.evaluerDemande(
                id, evaluateurId, decision, commentaire, montantApprouve);
            
            return Response.ok(demandeEvaluee).build();
            
        } catch (IllegalArgumentException | IllegalStateException e) {
            LOG.warnf("Évaluation invalide pour la demande %s: %s", id, e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                          .entity(Map.of("erreur", e.getMessage()))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'évaluation de la demande: %s", id);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @GET
    @Path("/demandes")
    @Operation(summary = "Rechercher des demandes d'aide", 
               description = "Recherche des demandes d'aide avec filtres")
    @APIResponse(responseCode = "200", description = "Liste des demandes")
    public Response rechercherDemandes(@QueryParam("organisationId") String organisationId,
                                      @QueryParam("typeAide") String typeAide,
                                      @QueryParam("statut") String statut,
                                      @QueryParam("demandeurId") String demandeurId,
                                      @QueryParam("urgente") Boolean urgente,
                                      @QueryParam("page") @DefaultValue("0") int page,
                                      @QueryParam("taille") @DefaultValue("20") int taille) {
        LOG.debugf("Recherche de demandes avec filtres");
        
        try {
            Map<String, Object> filtres = Map.of(
                "organisationId", organisationId != null ? organisationId : "",
                "typeAide", typeAide != null ? TypeAide.valueOf(typeAide) : "",
                "statut", statut != null ? StatutAide.valueOf(statut) : "",
                "demandeurId", demandeurId != null ? demandeurId : "",
                "urgente", urgente != null ? urgente : false,
                "page", page,
                "taille", taille
            );
            
            List<DemandeAideDTO> demandes = solidariteService.rechercherDemandes(filtres);
            
            return Response.ok(Map.of(
                "demandes", demandes,
                "page", page,
                "taille", taille,
                "total", demandes.size()
            )).build();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la recherche de demandes");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    // === ENDPOINTS PROPOSITIONS D'AIDE ===
    
    @POST
    @Path("/propositions")
    @Operation(summary = "Créer une nouvelle proposition d'aide", 
               description = "Crée une nouvelle proposition d'aide")
    @APIResponse(responseCode = "201", description = "Proposition créée avec succès")
    @APIResponse(responseCode = "400", description = "Données invalides")
    public Response creerPropositionAide(@Valid PropositionAideDTO propositionDTO) {
        LOG.infof("Création d'une nouvelle proposition d'aide: %s", propositionDTO.getTitre());
        
        try {
            PropositionAideDTO propositionCreee = solidariteService.creerPropositionAide(propositionDTO);
            return Response.status(Response.Status.CREATED)
                          .entity(propositionCreee)
                          .build();
                          
        } catch (IllegalArgumentException e) {
            LOG.warnf("Données invalides pour la création de proposition: %s", e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                          .entity(Map.of("erreur", e.getMessage()))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la création de proposition d'aide");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @GET
    @Path("/propositions/{id}")
    @Operation(summary = "Obtenir une proposition d'aide par ID", 
               description = "Récupère les détails d'une proposition d'aide spécifique")
    @APIResponse(responseCode = "200", description = "Proposition trouvée")
    @APIResponse(responseCode = "404", description = "Proposition non trouvée")
    public Response obtenirPropositionAide(@PathParam("id") @NotBlank String id) {
        LOG.debugf("Récupération de la proposition d'aide: %s", id);
        
        try {
            PropositionAideDTO proposition = solidariteService.obtenirPropositionAide(id);
            
            if (proposition == null) {
                return Response.status(Response.Status.NOT_FOUND)
                              .entity(Map.of("erreur", "Proposition non trouvée"))
                              .build();
            }
            
            return Response.ok(proposition).build();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la récupération de la proposition: %s", id);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @GET
    @Path("/propositions")
    @Operation(summary = "Rechercher des propositions d'aide", 
               description = "Recherche des propositions d'aide avec filtres")
    @APIResponse(responseCode = "200", description = "Liste des propositions")
    public Response rechercherPropositions(@QueryParam("organisationId") String organisationId,
                                          @QueryParam("typeAide") String typeAide,
                                          @QueryParam("proposantId") String proposantId,
                                          @QueryParam("actives") @DefaultValue("true") Boolean actives,
                                          @QueryParam("page") @DefaultValue("0") int page,
                                          @QueryParam("taille") @DefaultValue("20") int taille) {
        LOG.debugf("Recherche de propositions avec filtres");
        
        try {
            Map<String, Object> filtres = Map.of(
                "organisationId", organisationId != null ? organisationId : "",
                "typeAide", typeAide != null ? TypeAide.valueOf(typeAide) : "",
                "proposantId", proposantId != null ? proposantId : "",
                "estDisponible", actives,
                "page", page,
                "taille", taille
            );
            
            List<PropositionAideDTO> propositions = solidariteService.rechercherPropositions(filtres);
            
            return Response.ok(Map.of(
                "propositions", propositions,
                "page", page,
                "taille", taille,
                "total", propositions.size()
            )).build();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la recherche de propositions");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    // === ENDPOINTS MATCHING ===
    
    @GET
    @Path("/demandes/{id}/propositions-compatibles")
    @Operation(summary = "Trouver des propositions compatibles", 
               description = "Trouve les propositions compatibles avec une demande")
    @APIResponse(responseCode = "200", description = "Propositions compatibles trouvées")
    @APIResponse(responseCode = "404", description = "Demande non trouvée")
    public Response trouverPropositionsCompatibles(@PathParam("id") @NotBlank String demandeId) {
        LOG.infof("Recherche de propositions compatibles pour la demande: %s", demandeId);
        
        try {
            List<PropositionAideDTO> propositionsCompatibles = 
                solidariteService.trouverPropositionsCompatibles(demandeId);
            
            return Response.ok(Map.of(
                "demandeId", demandeId,
                "propositionsCompatibles", propositionsCompatibles,
                "nombreResultats", propositionsCompatibles.size()
            )).build();
            
        } catch (IllegalArgumentException e) {
            return Response.status(Response.Status.NOT_FOUND)
                          .entity(Map.of("erreur", "Demande non trouvée"))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la recherche de propositions compatibles");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    @GET
    @Path("/propositions/{id}/demandes-compatibles")
    @Operation(summary = "Trouver des demandes compatibles", 
               description = "Trouve les demandes compatibles avec une proposition")
    @APIResponse(responseCode = "200", description = "Demandes compatibles trouvées")
    @APIResponse(responseCode = "404", description = "Proposition non trouvée")
    public Response trouverDemandesCompatibles(@PathParam("id") @NotBlank String propositionId) {
        LOG.infof("Recherche de demandes compatibles pour la proposition: %s", propositionId);
        
        try {
            List<DemandeAideDTO> demandesCompatibles = 
                solidariteService.trouverDemandesCompatibles(propositionId);
            
            return Response.ok(Map.of(
                "propositionId", propositionId,
                "demandesCompatibles", demandesCompatibles,
                "nombreResultats", demandesCompatibles.size()
            )).build();
            
        } catch (IllegalArgumentException e) {
            return Response.status(Response.Status.NOT_FOUND)
                          .entity(Map.of("erreur", "Proposition non trouvée"))
                          .build();
                          
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la recherche de demandes compatibles");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
    
    // === ENDPOINTS STATISTIQUES ===
    
    @GET
    @Path("/statistiques/{organisationId}")
    @Operation(summary = "Obtenir les statistiques de solidarité", 
               description = "Récupère les statistiques complètes du système de solidarité")
    @APIResponse(responseCode = "200", description = "Statistiques récupérées")
    public Response obtenirStatistiquesSolidarite(@PathParam("organisationId") @NotBlank String organisationId) {
        LOG.infof("Récupération des statistiques de solidarité pour: %s", organisationId);
        
        try {
            Map<String, Object> statistiques = solidariteService.obtenirStatistiquesSolidarite(organisationId);
            return Response.ok(statistiques).build();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la récupération des statistiques");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                          .entity(Map.of("erreur", "Erreur interne du serveur"))
                          .build();
        }
    }
}
