CodeService.java

package com.archiweb.service;

import com.archiweb.model.Code;
import com.archiweb.model.PrizeType;
import com.archiweb.repository.CodeRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class CodeService {

    private final CodeRepository repo;

    public CodeService(CodeRepository repo) {
        this.repo = repo;
    }

    // ✅ Récupération paginée et filtrée
    public Page<Code> getCodesFiltered(PrizeType prizeType, Boolean used, int page, int size) {
        PageRequest pageable = PageRequest.of(page, size);

        if (prizeType != null && used != null) {
            return repo.findByPrizeTypeAndUsed(prizeType, used, pageable); // ✅ corrigé
        } else if (prizeType != null) {
            return repo.findByPrizeType(prizeType, pageable);
        } else if (used != null) {
            return repo.findByUsed(used, pageable); // ✅ corrigé
        } else {
            return repo.findAll(pageable);
        }
    }

    // ✅ Vérifie un code (réutilisé par le contrôleur)
    public Code verifyCode(String valeur) {
        Optional<Code> opt = repo.findByValeur(valeur.trim().toUpperCase());
        if (opt.isEmpty()) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Code inconnu.");
        }

        Code code = opt.get();

        if (code.getExpiresAt() != null && code.getExpiresAt().isBefore(LocalDateTime.now())) {
            throw new ResponseStatusException(HttpStatus.GONE, "Code expiré ❌");
        }

        if (code.isUsed()) {
            throw new ResponseStatusException(HttpStatus.CONFLICT, "Code déjà utilisé ❗");
        }

        return code;
    }

    // ✅ Marque un code comme utilisé
    public void markCodeUsed(Code code) {
        code.setUsed(true);
        code.setUsedAt(LocalDateTime.now());
        repo.save(code);
    }

    // ✅ Crée un nouveau code
    public Code createCode(Code code) {
        if (repo.findByValeur(code.getValeur().toUpperCase()).isPresent()) {
            throw new ResponseStatusException(HttpStatus.CONFLICT, "Valeur de code déjà existante.");
        }

        code.setValeur(code.getValeur().toUpperCase());
        if (code.getPrizeType() == null) {
            code.setPrizeType(PrizeType.INFUSEUR); // valeur par défaut
        }
        code.setUsed(false);
        code.setUsedAt(null);
        code.setExpiresAt(LocalDateTime.now().plusDays(60));

        return repo.save(code);
    }

    // ✅ Met à jour un code existant
    public Code updateCode(Long id, Code newCode) {
        Code existing = repo.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Code introuvable."));

        if (newCode.getPrizeType() != null) {
            existing.setPrizeType(newCode.getPrizeType());
        }
        if (newCode.getExpiresAt() != null) {
            existing.setExpiresAt(newCode.getExpiresAt());
        }
        existing.setUsed(newCode.isUsed());
        existing.setUsedAt(newCode.getUsedAt());

        return repo.save(existing);
    }

    // ✅ Supprime un code
    public void deleteCode(Long id) {
        if (!repo.existsById(id)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Code introuvable.");
        }
        repo.deleteById(id);
    }

    // ✅ Cherche un code par valeur exacte
    public Optional<Code> findByValeur(String valeur) {
        return repo.findByValeur(valeur.trim().toUpperCase());
    }

    // ✅ Récupère tous les codes expirés
    public List<Code> getExpiredCodes() {
        return repo.findAll().stream()
                .filter(c -> c.getExpiresAt() != null && c.getExpiresAt().isBefore(LocalDateTime.now()))
                .toList();
    }
}