package com.saas.admin.service;

import com.saas.admin.entity.RefreshToken;
import com.saas.admin.entity.User;
import com.saas.admin.repository.RefreshTokenRepository;
import com.saas.shared.exception.BusinessException;
import com.saas.shared.exception.ErrorCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.SecureRandom;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Optional;

@Service
public class RefreshTokenService {

    @Autowired
    private RefreshTokenRepository refreshTokenRepository;

    @Value("${security.refresh-token.expiration-days:30}")
    private int refreshTokenExpirationDays;

    private final SecureRandom secureRandom = new SecureRandom();

    @Transactional
    public String createRefreshToken(User user) {
        // create a secure random token
        byte[] random = new byte[64];
        secureRandom.nextBytes(random);
        String token = Base64.getUrlEncoder().withoutPadding().encodeToString(random);

        RefreshToken rt = new RefreshToken();
        rt.setToken(token);
        rt.setUserId(user.getId());
        rt.setUserEmail(user.getEmail());
        rt.setExpiresAt(Instant.now().plus(refreshTokenExpirationDays, ChronoUnit.DAYS));

        refreshTokenRepository.save(rt);
        return token;
    }

    public RefreshToken validateRefreshToken(String token) {
        Optional<RefreshToken> maybe = refreshTokenRepository.findByToken(token);
        if (maybe.isEmpty()) {
            throw new BusinessException(ErrorCode.INVALID_TOKEN, "Refresh token not found");
        }

        RefreshToken rt = maybe.get();
        if (rt.isRevoked() || rt.getExpiresAt().isBefore(Instant.now())) {
            throw new BusinessException(ErrorCode.INVALID_TOKEN, "Refresh token revoked or expired");
        }
        return rt;
    }

    @Transactional
    public void revokeRefreshToken(String token) {
        Optional<RefreshToken> maybe = refreshTokenRepository.findByToken(token);
        if (maybe.isPresent()) {
            RefreshToken rt = maybe.get();
            rt.setRevoked(true);
            refreshTokenRepository.save(rt);
        }
    }

    @Transactional
    public void revokeAllForUser(Long userId) {
        refreshTokenRepository.deleteByUserId(userId);
    }
}
