package gc.mda.kcg.auth.provider;

import gc.mda.kcg.auth.User;
import gc.mda.kcg.auth.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.OffsetDateTime;

/**
 * 자체 ID/PW 인증 (BCrypt).
 * Phase 1 인증 방식 — Phase 9에서 GPKI/SSO 추가 예정.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PasswordAuthProvider implements AuthProvider {

    private static final int MAX_FAIL_ATTEMPTS = 5;

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    @Override
    public String getProviderType() {
        return "PASSWORD";
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = AuthenticationException.class)
    public User authenticate(AuthRequest request) {
        User user = userRepository.findByUserAcnt(request.userAcnt())
                .orElseThrow(() -> new AuthenticationException("USER_NOT_FOUND"));

        // 상태 검증
        if (user.isLocked()) {
            throw new AuthenticationException("ACCOUNT_LOCKED");
        }
        if (!user.isActive()) {
            throw new AuthenticationException("ACCOUNT_NOT_ACTIVE:" + user.getUserSttsCd());
        }

        // PASSWORD provider만 처리
        if (!"PASSWORD".equals(user.getAuthProvider())) {
            throw new AuthenticationException("WRONG_PROVIDER:" + user.getAuthProvider());
        }

        // BCrypt 비교
        if (user.getPswdHash() == null || !passwordEncoder.matches(request.credential(), user.getPswdHash())) {
            int newFailCnt = user.getFailCnt() + 1;
            user.setFailCnt(newFailCnt);
            if (newFailCnt >= MAX_FAIL_ATTEMPTS) {
                user.setUserSttsCd("LOCKED");
                userRepository.save(user);
                throw new AuthenticationException("MAX_FAIL_LOCKED");
            }
            userRepository.save(user);
            throw new AuthenticationException("WRONG_PASSWORD:" + newFailCnt);
        }

        // 로그인 성공: 실패 카운터 초기화 + 마지막 로그인 시각 갱신
        user.setFailCnt(0);
        user.setLastLoginDtm(OffsetDateTime.now());
        userRepository.save(user);
        return user;
    }
}
