package mx.gob.slp.baseadminweb.application.service;

import mx.gob.slp.baseadminweb.domain.model.PassCode;
import mx.gob.slp.baseadminweb.domain.repository.PassCodeRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.SecureRandom;
import java.time.Instant;
import java.util.List;

@Service
public class PassCodeService {

    private static final String CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    private static final int CODE_LENGTH = 10;
    private static final int MAX_GENERATION_ATTEMPTS = 20;

    private final PassCodeRepository passCodeRepository;
    private final SecureRandom secureRandom = new SecureRandom();

    public PassCodeService(PassCodeRepository passCodeRepository) {
        this.passCodeRepository = passCodeRepository;
    }

    public List<PassCode> findAll() {
        return passCodeRepository.findAll();
    }

    @Transactional
    public PassCode create(String name) {
        String trimmedName = name == null ? "" : name.trim();
        if (trimmedName.isEmpty()) {
            throw new IllegalArgumentException("El nombre del codigo pase es obligatorio.");
        }

        PassCode passCode = new PassCode(trimmedName, generateUniqueCode(), Instant.now());
        return passCodeRepository.save(passCode);
    }

    @Transactional
    public PassCode scan(String code) {
        String trimmedCode = code == null ? "" : code.trim().toUpperCase();
        if (trimmedCode.isEmpty()) {
            throw new IllegalArgumentException("El codigo es obligatorio.");
        }

        PassCode passCode = passCodeRepository.findByCode(trimmedCode)
                .orElseThrow(() -> new IllegalArgumentException("Codigo pase no encontrado."));

        if (passCode.isScanned()) {
            throw new IllegalStateException("El codigo pase ya fue escaneado.");
        }

        passCode.markAsUsed(Instant.now());
        return passCodeRepository.save(passCode);
    }

    private String generateUniqueCode() {
        for (int attempt = 0; attempt < MAX_GENERATION_ATTEMPTS; attempt++) {
            String candidate = randomCode();
            if (!passCodeRepository.existsByCode(candidate)) {
                return candidate;
            }
        }
        throw new IllegalStateException("No fue posible generar un codigo unico.");
    }

    private String randomCode() {
        StringBuilder builder = new StringBuilder(CODE_LENGTH);
        for (int i = 0; i < CODE_LENGTH; i++) {
            int index = secureRandom.nextInt(CODE_ALPHABET.length());
            builder.append(CODE_ALPHABET.charAt(index));
        }
        return builder.toString();
    }
}