package kr.co.accura.wbx.spring.auth;

import kr.co.accura.wbx.spring.common.BusinessException;
import kr.co.accura.wbx.spring.config.WbxSpringProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class RefreshTokenService {

    private final RefreshTokenRepository repository;
    private final WbxUserRepository userRepository;
    private final JwtProvider jwtProvider;
    private final WbxSpringProperties props;

    /**
     * Refresh Token 생성
     */
    public String create(Long userId, String deviceInfo, String ip) {
        String rawToken = UUID.randomUUID().toString();
        String hash = sha256(rawToken);

        repository.save(WbxRefreshToken.builder()
                .userId(userId)
                .tokenHash(hash)
                .deviceInfo(deviceInfo)
                .ipAddress(ip)
                .expiresAt(LocalDateTime.now().plusSeconds(props.getJwt().getRefreshExpiration()))
                .build());

        return rawToken;
    }

    /**
     * Refresh Token으로 Access Token 재발급
     */
    public String refresh(String rawToken) {
        String hash = sha256(rawToken);
        WbxRefreshToken stored = repository.findByTokenHash(hash)
                .filter(t -> !t.isRevoked() && t.getExpiresAt().isAfter(LocalDateTime.now()))
                .orElseThrow(() -> new BusinessException("Invalid or expired refresh token"));

        WbxUser user = userRepository.findById(stored.getUserId())
                .orElseThrow(() -> new BusinessException("User not found"));

        return jwtProvider.generateToken(user.toUserDetails());
    }

    /**
     * Refresh Token 해지 (로그아웃)
     */
    public void revoke(String rawToken) {
        String hash = sha256(rawToken);
        repository.findByTokenHash(hash)
                .ifPresent(t -> {
                    t.setRevoked(true);
                    repository.save(t);
                });
    }

    /**
     * 전체 디바이스 로그아웃
     */
    public void revokeAll(Long userId) {
        repository.revokeAllByUserId(userId);
    }

    private String sha256(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(input.getBytes());
            return new String(Hex.encode(hash));
        } catch (Exception e) {
            throw new RuntimeException("SHA-256 failed", e);
        }
    }
}
