SchedulerService.java

package com.archiweb.service;

import com.archiweb.model.Code;
import com.archiweb.model.Draw;
import com.archiweb.model.User;
import com.archiweb.model.Win;
import com.archiweb.repository.CodeRepository;
import com.archiweb.repository.DrawRepository;
import com.archiweb.repository.UserRepository;
import com.archiweb.repository.WinRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;

@Service
@Slf4j
public class SchedulerService {

    private final CodeRepository codeRepository;
    private final WinRepository winRepository;
    private final UserRepository userRepository;
    private final DrawRepository drawRepository;

    // 📅 date du début du jeu – à adapter selon ton contexte
    private static final LocalDate GAME_START_DATE = LocalDate.of(2025, 10, 1);
    private static final LocalDate GAME_END_DATE = GAME_START_DATE.plusDays(30);

    public SchedulerService(CodeRepository codeRepository,
                            WinRepository winRepository,
                            UserRepository userRepository,
                            DrawRepository drawRepository) {
        this.codeRepository = codeRepository;
        this.winRepository = winRepository;
        this.userRepository = userRepository;
        this.drawRepository = drawRepository;
    }

    // 🕒 1. Clôture automatique du jeu après 30 jours
    @Scheduled(cron = "0 0 0 * * *") // chaque jour à minuit
    public void closeGameIfExpired() {
        LocalDate today = LocalDate.now();

        if (today.isAfter(GAME_END_DATE)) {
            long activeCodes = codeRepository.countByUsed(false);
            log.info("🚫 Le jeu est terminé depuis le {}, désactivation automatique.", GAME_END_DATE);
            log.info("🔒 {} codes non utilisés seront désormais considérés comme invalides.", activeCodes);
        } else {
            long remainingDays = GAME_END_DATE.toEpochDay() - today.toEpochDay();
            log.info("⏳ Le jeu est encore ouvert. {} jour(s) restant(s) avant la clôture.", remainingDays);
        }
    }

    // 🎰 2. Tirage automatique du gagnant final
    @Scheduled(cron = "0 5 0 * * *") // chaque jour à 00h05
    public void performAutomaticFinalDraw() {
        LocalDate today = LocalDate.now();

        if (today.isAfter(GAME_END_DATE)) {
            if (drawRepository.existsByType("FINAL")) {
                log.info("🏁 Le tirage final a déjà été effectué.");
                return;
            }

            List<Win> allWins = winRepository.findAll();
            if (allWins.isEmpty()) {
                log.warn("⚠️ Aucun participant trouvé — tirage final non effectué.");
                return;
            }

            Random random = new Random();
            Win selectedWin = allWins.get(random.nextInt(allWins.size()));
            User winner = selectedWin.getUser();

            Draw draw = new Draw();
            draw.setType("FINAL");
            draw.setWinner(winner);
            draw.setCreatedAt(LocalDateTime.now());
            drawRepository.save(draw);

            log.info("🎉 Tirage final automatique effectué ! Gagnant : {} ({})",
                    winner.getUsername(), winner.getEmail());
        }
    }

    // 🧹 3. Nettoyage des codes expirés / données obsolètes
    @Scheduled(cron = "0 30 2 * * *") // chaque jour à 2h30 du matin
    public void cleanExpiredCodes() {
        List<Code> expiredCodes = codeRepository.findAll().stream()
                .filter(code -> code.getExpiresAt() != null &&
                        code.getExpiresAt().isBefore(LocalDateTime.now()))
                .toList();

        if (expiredCodes.isEmpty()) {
            log.info("🧹 Aucun code expiré à nettoyer aujourd’hui.");
            return;
        }

        log.info("🧹 Nettoyage de {} codes expirés...", expiredCodes.size());
        codeRepository.deleteAll(expiredCodes);
        log.info("✅ Nettoyage terminé à {}", LocalDateTime.now());
    }
}