AdminController.java

package com.archiweb.api;

import com.archiweb.service.EmailExportService;
import com.archiweb.service.StatsService;
import com.archiweb.service.DrawService;
import com.archiweb.service.SettingsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/admin")
@Tag(
        name = "Administration",
        description = """
        Module d’administration du jeu concours Thé Tip Top.  
        Ce contrôleur regroupe les fonctionnalités réservées aux administrateurs :
        - Export des emails opt-in pour les campagnes marketing (RGPD).  
        - Consultation des statistiques globales de participations et de gains.  
        - Lancement du tirage final automatique du jeu concours.  
        Tous les endpoints nécessitent le rôle **ADMIN**.
        """
)
public class AdminController {

    private final EmailExportService emailExportService;
    private final StatsService statsService;
    private final DrawService drawService;
    private final SettingsService settingsService;

    public AdminController(EmailExportService emailExportService,
                           StatsService statsService,
                           DrawService drawService,
                           SettingsService settingsService) {
        this.emailExportService = emailExportService;
        this.statsService = statsService;
        this.drawService = drawService;
        this.settingsService = settingsService;
    }

    // =========================================================
    // Endpoint de test pour vérifier les permissions
    // =========================================================
    @GetMapping("/test-auth")
    @Operation(summary = "Test d'authentification admin", description = "Endpoint de test pour vérifier que l'utilisateur a bien le rôle ADMIN")
    public ResponseEntity<Map<String, Object>> testAuth(Authentication authentication) {
        Map<String, Object> response = new HashMap<>();
        response.put("authenticated", authentication != null);
        response.put("name", authentication != null ? authentication.getName() : null);
        response.put("authorities", authentication != null ? 
            authentication.getAuthorities().stream()
                .map(a -> a.getAuthority())
                .collect(java.util.stream.Collectors.toList()) : null);
        response.put("hasAdminRole", authentication != null && 
            authentication.getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN")));
        return ResponseEntity.ok(response);
    }

    // =========================================================
    // Export des emails opt-in
    // =========================================================
    @Operation(
            summary = "Exporter les emails opt-in",
            description = """
            Permet d’exporter la liste complète des utilisateurs ayant accepté de recevoir des e-mails marketing (`consentGiven = true`).  
            Le fichier exporté contient les adresses e-mail valides et peut être utilisé pour des campagnes RGPD-compliantes.
            """,
            responses = {
                    @ApiResponse(
                            responseCode = "200",
                            description = "Export des emails effectué avec succès",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(
                                            value = """
                                            {
                                              "status": "success",
                                              "count": 145,
                                              "filePath": "/exports/emailing_2025-10-27.csv"
                                            }
                                            """
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = "403",
                            description = "Accès refusé : rôle ADMIN requis",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(
                                            value = "{ \"error\": \"Access denied. ADMIN role required.\" }"
                                    )
                            )
                    )
            }
    )
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/export-emailing")
    public ResponseEntity<?> exportEmails() {
        return ResponseEntity.ok(emailExportService.exportEmailing());
    }

    // =========================================================
    // Statistiques globales
    // =========================================================
    @Operation(
            summary = "Obtenir les statistiques globales",
            description = """
            Retourne un ensemble complet de statistiques sur les participations, les lots gagnés, les boutiques participantes et la période de jeu.  
            Les paramètres optionnels permettent de filtrer les résultats :
            - **lot** : type de lot (ex. INFUSEUR, COFFRET_39)  
            - **boutique** : identifiant ou nom de la boutique  
            - **periode** : intervalle temporel (ex. "2025-09-01:2025-09-30")
            """,
            responses = {
                    @ApiResponse(
                            responseCode = "200",
                            description = "Statistiques récupérées avec succès",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(
                                            value = """
                                            {
                                              "status": "success",
                                              "totalParticipations": 12054,
                                              "totalGagnants": 354,
                                              "topBoutique": "Boutique Paris 12",
                                              "lotsDistribues": {
                                                "INFUSEUR": 220,
                                                "COFFRET_39": 102,
                                                "COFFRET_99": 32
                                              }
                                            }
                                            """
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = "403",
                            description = "Accès refusé : rôle ADMIN requis",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(value = "{ \"error\": \"Access denied. ADMIN role required.\" }")
                            )
                    )
            }
    )
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/stats")
    public ResponseEntity<?> getStats(@RequestParam(required = false) String lot,
                                      @RequestParam(required = false) String boutique,
                                      @RequestParam(required = false) String periode) {
        return ResponseEntity.ok(statsService.getStats(lot, boutique, periode));
    }

    // =========================================================
    // Tirage final du jeu concours
    // =========================================================
    @Operation(
            summary = "Effectuer le tirage final",
            description = """
            Lance le **tirage automatique du gagnant final** du jeu concours.  
            Ce processus sélectionne un gagnant parmi toutes les participations valides selon les règles de probabilité définies.  
            Un paramètre optionnel `seed` peut être fourni pour rendre le tirage reproductible lors des tests.
            """,
            responses = {
                    @ApiResponse(
                            responseCode = "200",
                            description = "Tirage final effectué avec succès",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(
                                            value = """
                                            {
                                              "status": "success",
                                              "winner": {
                                                "id": 42,
                                                "email": "gagnant@example.com",
                                                "prize": "COFFRET_99",
                                                "drawDate": "2025-10-27T10:32:45"
                                              }
                                            }
                                            """
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = "403",
                            description = "Accès refusé : rôle ADMIN requis",
                            content = @Content(
                                    mediaType = "application/json",
                                    examples = @ExampleObject(value = "{ \"error\": \"Access denied. ADMIN role required.\" }")
                            )
                    )
            }
    )
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/draw/final")
    public ResponseEntity<?> runFinalDraw(@RequestParam(required = false) Long seed) {
        return ResponseEntity.ok(drawService.runFinalDraw(seed));
    }

    // =========================================================
    // Gestion du mode Noël
    // =========================================================
    @Operation(
            summary = "Activer/Désactiver le mode Noël",
            description = "Active ou désactive le mode Noël pour le site (accessible à tous les utilisateurs authentifiés)"
    )
    // Pas de @PreAuthorize - accessible à tous les utilisateurs authentifiés
    // Le mode Noël est juste un paramètre visuel, pas besoin de restriction admin
    @PostMapping("/settings/christmas-mode")
    public ResponseEntity<Map<String, Object>> setChristmasMode(@RequestBody Map<String, Boolean> request) {
        Boolean enabled = request.get("enabled");
        if (enabled == null) {
            Map<String, Object> error = new HashMap<>();
            error.put("error", "Le paramètre 'enabled' est requis");
            return ResponseEntity.badRequest().body(error);
        }
        
        settingsService.setChristmasMode(enabled);
        Map<String, Object> response = new HashMap<>();
        response.put("success", true);
        response.put("enabled", enabled);
        response.put("message", enabled ? "Mode Noël activé" : "Mode Noël désactivé");
        return ResponseEntity.ok(response);
    }
}