package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.entity.Evenement;
import dev.lions.unionflow.server.entity.Evenement.StatutEvenement;
import dev.lions.unionflow.server.entity.Evenement.TypeEvenement;
import dev.lions.unionflow.server.service.EvenementService;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * Resource REST pour la gestion des événements
 * 
 * Fournit les endpoints API pour les opérations CRUD sur les événements,
 * optimisé pour l'intégration avec l'application mobile UnionFlow.
 * 
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-15
 */
@Path("/api/evenements")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Événements", description = "Gestion des événements de l'union")
public class EvenementResource {

    private static final Logger LOG = Logger.getLogger(EvenementResource.class);

    @Inject
    EvenementService evenementService;

    /**
     * Endpoint de test public pour vérifier la connectivité
     */
    @GET
    @Path("/test")
    @Operation(summary = "Test de connectivité", description = "Endpoint public pour tester la connectivité")
    @APIResponse(responseCode = "200", description = "Test réussi")
    public Response testConnectivity() {
        LOG.info("Test de connectivité appelé depuis l'application mobile");
        return Response.ok(Map.of(
            "status", "success",
            "message", "Serveur UnionFlow opérationnel",
            "timestamp", System.currentTimeMillis(),
            "version", "1.0.0"
        )).build();
    }

    /**
     * Endpoint temporaire pour les événements à venir (sans authentification)
     */
    @GET
    @Path("/a-venir-public")
    @Operation(summary = "Événements à venir (public)", description = "Liste des événements à venir sans authentification")
    @APIResponse(responseCode = "200", description = "Liste des événements")
    public Response getEvenementsAVenirPublic(
            @QueryParam("page") @DefaultValue("0") @Min(0) int page,
            @QueryParam("size") @DefaultValue("10") @Min(1) int size) {

        try {
            LOG.infof("GET /api/evenements/a-venir-public - page: %d, size: %d", page, size);

            // Créer des données de test pour l'application mobile (format List direct)
            List<Map<String, Object>> evenements = new ArrayList<>();

            Map<String, Object> event1 = new HashMap<>();
            event1.put("id", "1");
            event1.put("titre", "Assemblée Générale 2025");
            event1.put("description", "Assemblée générale annuelle de l'union");
            event1.put("dateDebut", "2025-02-15T09:00:00");
            event1.put("dateFin", "2025-02-15T17:00:00");
            event1.put("lieu", "Salle de conférence principale");
            event1.put("statut", "PLANIFIE");
            event1.put("typeEvenement", "ASSEMBLEE_GENERALE");
            event1.put("inscriptionRequise", false);
            event1.put("visiblePublic", true);
            event1.put("actif", true);
            evenements.add(event1);

            Map<String, Object> event2 = new HashMap<>();
            event2.put("id", "2");
            event2.put("titre", "Formation Gestion Financière");
            event2.put("description", "Formation sur la gestion financière des unions");
            event2.put("dateDebut", "2025-02-20T14:00:00");
            event2.put("dateFin", "2025-02-20T18:00:00");
            event2.put("lieu", "Centre de formation");
            event2.put("statut", "PLANIFIE");
            event2.put("typeEvenement", "FORMATION");
            event2.put("inscriptionRequise", true);
            event2.put("visiblePublic", true);
            event2.put("actif", true);
            evenements.add(event2);

            Map<String, Object> event3 = new HashMap<>();
            event3.put("id", "3");
            event3.put("titre", "Réunion Mensuelle");
            event3.put("description", "Réunion mensuelle des membres");
            event3.put("dateDebut", "2025-02-25T19:00:00");
            event3.put("dateFin", "2025-02-25T21:00:00");
            event3.put("lieu", "Siège de l'union");
            event3.put("statut", "PLANIFIE");
            event3.put("typeEvenement", "REUNION");
            event3.put("inscriptionRequise", false);
            event3.put("visiblePublic", true);
            event3.put("actif", true);
            evenements.add(event3);

            // Retourner directement la liste (pas d'objet de pagination)
            return Response.ok(evenements).build();

        } catch (Exception e) {
            LOG.errorf("Erreur lors de la récupération des événements publics: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération des événements"))
                    .build();
        }
    }

    /**
     * Liste tous les événements actifs avec pagination
     */
    @GET
    @Operation(summary = "Lister tous les événements actifs", 
               description = "Récupère la liste paginée des événements actifs")
    @APIResponse(responseCode = "200", description = "Liste des événements actifs")
    @APIResponse(responseCode = "401", description = "Non authentifié")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT", "MEMBRE"})
    public Response listerEvenements(
            @Parameter(description = "Numéro de page (0-based)", example = "0")
            @QueryParam("page") @DefaultValue("0") @Min(0) int page,
            
            @Parameter(description = "Taille de la page", example = "20")
            @QueryParam("size") @DefaultValue("20") @Min(1) int size,
            
            @Parameter(description = "Champ de tri", example = "dateDebut")
            @QueryParam("sort") @DefaultValue("dateDebut") String sortField,
            
            @Parameter(description = "Direction du tri (asc/desc)", example = "asc")
            @QueryParam("direction") @DefaultValue("asc") String sortDirection) {
        
        try {
            LOG.infof("GET /api/evenements - page: %d, size: %d", page, size);
            
            Sort sort = sortDirection.equalsIgnoreCase("desc") 
                ? Sort.by(sortField).descending() 
                : Sort.by(sortField).ascending();
            
            List<Evenement> evenements = evenementService.listerEvenementsActifs(
                Page.of(page, size), sort);
            
            return Response.ok(evenements).build();
            
        } catch (Exception e) {
            LOG.errorf("Erreur lors de la récupération des événements: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération des événements"))
                    .build();
        }
    }

    /**
     * Récupère un événement par son ID
     */
    @GET
    @Path("/{id}")
    @Operation(summary = "Récupérer un événement par ID")
    @APIResponse(responseCode = "200", description = "Événement trouvé")
    @APIResponse(responseCode = "404", description = "Événement non trouvé")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT", "MEMBRE"})
    public Response obtenirEvenement(
            @Parameter(description = "ID de l'événement", required = true)
            @PathParam("id") Long id) {
        
        try {
            LOG.infof("GET /api/evenements/%d", id);
            
            Optional<Evenement> evenement = evenementService.trouverParId(id);
            
            if (evenement.isPresent()) {
                return Response.ok(evenement.get()).build();
            } else {
                return Response.status(Response.Status.NOT_FOUND)
                        .entity(Map.of("error", "Événement non trouvé"))
                        .build();
            }
            
        } catch (Exception e) {
            LOG.errorf("Erreur lors de la récupération de l'événement %d: %s", id, e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération de l'événement"))
                    .build();
        }
    }

    /**
     * Crée un nouvel événement
     */
    @POST
    @Operation(summary = "Créer un nouvel événement")
    @APIResponse(responseCode = "201", description = "Événement créé avec succès")
    @APIResponse(responseCode = "400", description = "Données invalides")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT"})
    public Response creerEvenement(
            @Parameter(description = "Données de l'événement à créer", required = true)
            @Valid Evenement evenement) {
        
        try {
            LOG.infof("POST /api/evenements - Création événement: %s", evenement.getTitre());
            
            Evenement evenementCree = evenementService.creerEvenement(evenement);
            
            return Response.status(Response.Status.CREATED)
                    .entity(evenementCree)
                    .build();
            
        } catch (IllegalArgumentException e) {
            LOG.warnf("Données invalides: %s", e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (SecurityException e) {
            LOG.warnf("Permissions insuffisantes: %s", e.getMessage());
            return Response.status(Response.Status.FORBIDDEN)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (Exception e) {
            LOG.errorf("Erreur lors de la création: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la création de l'événement"))
                    .build();
        }
    }

    /**
     * Met à jour un événement existant
     */
    @PUT
    @Path("/{id}")
    @Operation(summary = "Mettre à jour un événement")
    @APIResponse(responseCode = "200", description = "Événement mis à jour avec succès")
    @APIResponse(responseCode = "404", description = "Événement non trouvé")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT"})
    public Response mettreAJourEvenement(
            @PathParam("id") Long id,
            @Valid Evenement evenement) {
        
        try {
            LOG.infof("PUT /api/evenements/%d", id);
            
            Evenement evenementMisAJour = evenementService.mettreAJourEvenement(id, evenement);
            
            return Response.ok(evenementMisAJour).build();
            
        } catch (IllegalArgumentException e) {
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (SecurityException e) {
            return Response.status(Response.Status.FORBIDDEN)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (Exception e) {
            LOG.errorf("Erreur lors de la mise à jour: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la mise à jour"))
                    .build();
        }
    }

    /**
     * Supprime un événement
     */
    @DELETE
    @Path("/{id}")
    @Operation(summary = "Supprimer un événement")
    @APIResponse(responseCode = "204", description = "Événement supprimé avec succès")
    @RolesAllowed({"ADMIN", "PRESIDENT", "ORGANISATEUR_EVENEMENT"})
    public Response supprimerEvenement(@PathParam("id") Long id) {
        
        try {
            LOG.infof("DELETE /api/evenements/%d", id);
            
            evenementService.supprimerEvenement(id);
            
            return Response.noContent().build();
            
        } catch (IllegalArgumentException e) {
            return Response.status(Response.Status.NOT_FOUND)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (IllegalStateException e) {
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (SecurityException e) {
            return Response.status(Response.Status.FORBIDDEN)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (Exception e) {
            LOG.errorf("Erreur lors de la suppression: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la suppression"))
                    .build();
        }
    }

    /**
     * Endpoints spécialisés pour l'application mobile
     */

    /**
     * Liste les événements à venir
     */
    @GET
    @Path("/a-venir")
    @Operation(summary = "Événements à venir")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT", "MEMBRE"})
    public Response evenementsAVenir(
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("10") int size) {
        
        try {
            List<Evenement> evenements = evenementService.listerEvenementsAVenir(
                Page.of(page, size), Sort.by("dateDebut").ascending());
            
            return Response.ok(evenements).build();
        } catch (Exception e) {
            LOG.errorf("Erreur événements à venir: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération"))
                    .build();
        }
    }

    /**
     * Liste les événements publics
     */
    @GET
    @Path("/publics")
    @Operation(summary = "Événements publics")
    public Response evenementsPublics(
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") int size) {
        
        try {
            List<Evenement> evenements = evenementService.listerEvenementsPublics(
                Page.of(page, size), Sort.by("dateDebut").ascending());
            
            return Response.ok(evenements).build();
        } catch (Exception e) {
            LOG.errorf("Erreur événements publics: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération"))
                    .build();
        }
    }

    /**
     * Recherche d'événements
     */
    @GET
    @Path("/recherche")
    @Operation(summary = "Rechercher des événements")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT", "MEMBRE"})
    public Response rechercherEvenements(
            @QueryParam("q") String recherche,
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") int size) {
        
        try {
            if (recherche == null || recherche.trim().isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST)
                        .entity(Map.of("error", "Le terme de recherche est obligatoire"))
                        .build();
            }
            
            List<Evenement> evenements = evenementService.rechercherEvenements(
                recherche, Page.of(page, size), Sort.by("dateDebut").ascending());
            
            return Response.ok(evenements).build();
        } catch (Exception e) {
            LOG.errorf("Erreur recherche: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la recherche"))
                    .build();
        }
    }

    /**
     * Événements par type
     */
    @GET
    @Path("/type/{type}")
    @Operation(summary = "Événements par type")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT", "MEMBRE"})
    public Response evenementsParType(
            @PathParam("type") TypeEvenement type,
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") int size) {
        
        try {
            List<Evenement> evenements = evenementService.listerParType(
                type, Page.of(page, size), Sort.by("dateDebut").ascending());
            
            return Response.ok(evenements).build();
        } catch (Exception e) {
            LOG.errorf("Erreur événements par type: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors de la récupération"))
                    .build();
        }
    }

    /**
     * Change le statut d'un événement
     */
    @PATCH
    @Path("/{id}/statut")
    @Operation(summary = "Changer le statut d'un événement")
    @RolesAllowed({"ADMIN", "PRESIDENT", "ORGANISATEUR_EVENEMENT"})
    public Response changerStatut(
            @PathParam("id") Long id,
            @QueryParam("statut") StatutEvenement nouveauStatut) {
        
        try {
            if (nouveauStatut == null) {
                return Response.status(Response.Status.BAD_REQUEST)
                        .entity(Map.of("error", "Le nouveau statut est obligatoire"))
                        .build();
            }
            
            Evenement evenement = evenementService.changerStatut(id, nouveauStatut);
            
            return Response.ok(evenement).build();
        } catch (IllegalArgumentException e) {
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (SecurityException e) {
            return Response.status(Response.Status.FORBIDDEN)
                    .entity(Map.of("error", e.getMessage()))
                    .build();
        } catch (Exception e) {
            LOG.errorf("Erreur changement statut: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors du changement de statut"))
                    .build();
        }
    }

    /**
     * Statistiques des événements
     */
    @GET
    @Path("/statistiques")
    @Operation(summary = "Statistiques des événements")
    @RolesAllowed({"ADMIN", "PRESIDENT", "SECRETAIRE", "ORGANISATEUR_EVENEMENT"})
    public Response obtenirStatistiques() {
        
        try {
            Map<String, Object> statistiques = evenementService.obtenirStatistiques();
            
            return Response.ok(statistiques).build();
        } catch (Exception e) {
            LOG.errorf("Erreur statistiques: %s", e.getMessage());
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(Map.of("error", "Erreur lors du calcul des statistiques"))
                    .build();
        }
    }
}
