ParticipationController.java

package com.archiweb.api;

import com.archiweb.dto.*;
import com.archiweb.model.Code;
import com.archiweb.model.Participation;
import com.archiweb.model.User;
import com.archiweb.model.Win;
import com.archiweb.repository.CodeRepository;
import com.archiweb.repository.ParticipationRepository;
import com.archiweb.repository.UserRepository;
import com.archiweb.repository.WinRepository;
import com.archiweb.service.EmailService;
import com.archiweb.service.ParticipationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.*;

@RestController
@RequestMapping("/api/participations")
@Tag(
        name = "Participations",
        description = """
        Gestion complète des participations au jeu concours :
        - Enregistrement d'une nouvelle participation via un code
        - Consultation des participations d’un utilisateur
        - Validation de la remise d’un lot (claim)
        - Suppression d’une participation
        """
)
public class ParticipationController {

    private final EmailService emailService;
    private final ParticipationService participationService;
    private final UserRepository userRepository;
    private final CodeRepository codeRepository;
    private final ParticipationRepository participationRepository;
    private final WinRepository winRepository;

    public ParticipationController(EmailService emailService,
                                   ParticipationService participationService,
                                   UserRepository userRepository,
                                   CodeRepository codeRepository,
                                   ParticipationRepository participationRepository,
                                   WinRepository winRepository) {

        this.emailService = emailService;
        this.participationService = participationService;
        this.userRepository = userRepository;
        this.codeRepository = codeRepository;
        this.participationRepository = participationRepository;
        this.winRepository = winRepository;
    }

    // ================================================================
    // 1️⃣ Participer au jeu concours
    // ================================================================
    @PostMapping
    public ResponseEntity<?> participate(@RequestBody ParticipationRequest request) {

        String codeValeur = request.getCodeValeur();
        if (codeValeur == null || codeValeur.trim().isEmpty()) {
            return ResponseEntity.badRequest().body(Map.of("status", "error", "message", "Code vide ou invalide."));
        }

        User user = userRepository.findById(request.getUserId()).orElse(null);
        if (user == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(Map.of("status", "error", "message", "Utilisateur introuvable."));
        }

        Code code = codeRepository.findByValeur(codeValeur.trim().toUpperCase()).orElse(null);
        if (code == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(Map.of("status", "error", "message", "Code inconnu."));
        }

        if (code.getExpiresAt() != null && code.getExpiresAt().isBefore(LocalDateTime.now())) {
            return ResponseEntity.status(HttpStatus.GONE)
                    .body(Map.of("status", "expired", "message", "Ce code est expiré."));
        }

        if (code.isUsed()) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(Map.of("status", "used", "message", "Ce code a déjà été utilisé."));
        }

        if (participationRepository.findByUserAndCode(user, code).isPresent()) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(Map.of("status", "duplicate", "message", "Vous avez déjà utilisé ce code avec ce compte."));
        }

        // 🔥 MARQUER COMME UTILISÉ
        code.setUsed(true);
        code.setUsedAt(LocalDateTime.now());
        codeRepository.save(code);

        // 🔥 CRÉER UNE PARTICIPATION
        Participation participation = new Participation();
        participation.setUser(user);
        participation.setCode(code);
        participation.setPrizeName(code.getPrizeType().name());
        participation = participationRepository.save(participation);

        // 🔥 CRÉER UN WIN (gain) pour que l'employé puisse le scanner
        Win win = new Win();
        win.setUser(user);
        win.setPrizeName(code.getPrizeType().name());
        win.setClaimed(false);
        win.setCreatedAt(LocalDateTime.now());
        winRepository.save(win);

        // ⚠️ NE PAS ENVOYER L'EMAIL ICI - L'email sera envoyé après le choix de livraison par le frontend
        // L'email sera envoyé uniquement après que l'utilisateur ait choisi son mode de réception
        // (livraison à domicile ou récupération en boutique)

        // 🔥 RÉPONSE
        return ResponseEntity.ok(new ParticipationResponse(
                "success",
                participation.getId(),
                user.getEmail(),
                code.getValeur(),
                code.getPrizeType().name(),
                participation.isClaimed(),
                "Félicitations, participation enregistrée !"
        ));
    }

    // ================================================================
    // 2️⃣ Lister les participations d’un utilisateur
    // ================================================================
    @GetMapping
    public ResponseEntity<?> getParticipationsByUser(@RequestParam Long userId) {
        return userRepository.findById(userId)
                .map(user -> {
                    List<Participation> participations = participationRepository.findByUser(user);
                    return ResponseEntity.ok(Map.of("status", "success", "data", participations));
                })
                .orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(Map.of("status", "error", "message", "Utilisateur introuvable")));
    }

    // ================================================================
    // 3️⃣ Valider remise d’un lot
    // ================================================================
    @PostMapping("/{id}/claim")
    public ResponseEntity<?> claimPrize(@PathVariable Long id, @RequestBody ClaimPrizeRequest request) {
        return participationRepository.findById(id)
                .map(p -> {
                    if (p.isClaimed()) {
                        return ResponseEntity.status(HttpStatus.CONFLICT)
                                .body(Map.of("status", "already_claimed", "message", "Ce gain a déjà été remis"));
                    }

                    p.setClaimed(true);
                    p.setClaimedAt(LocalDateTime.now());
                    p.setStoreId(request.getStoreId());
                    p.setClaimedBy(request.getClaimedBy());
                    p.setClaimChannel(request.getChannel() != null ? request.getChannel() : "boutique");
                    participationRepository.save(p);

                    return ResponseEntity.ok(Map.of(
                            "status", "success",
                            "message", "Lot marqué comme remis",
                            "participationId", p.getId(),
                            "code", p.getCode().getValeur(),
                            "prizeType", p.getCode().getPrizeType().name()
                    ));
                })
                .orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(Map.of("status", "error", "message", "Participation introuvable")));
    }

    // ================================================================
    // 4️⃣ Supprimer une participation
    // ================================================================
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteParticipation(@PathVariable Long id) {
        return participationRepository.findById(id)
                .map(p -> {
                    participationRepository.delete(p);
                    return ResponseEntity.ok(Map.of("status", "success", "message", "Participation supprimée avec succès"));
                })
                .orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(Map.of("status", "error", "message", "Participation introuvable")));
    }
}