package com.kamco.cd.kamcoback.auth;

import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import java.time.ZonedDateTime;
import lombok.RequiredArgsConstructor;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {

  private final MembersRepository membersRepository;
  private final UserDetailsService userDetailsService;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String username = authentication.getName();
    String rawPassword = authentication.getCredentials().toString();

    // 1. 유저 조회
    MemberEntity member =
        membersRepository
            .findByUserId(username)
            .orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));

    // 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
    if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
      // 실패 카운트 저장
      int cnt = member.getLoginFailCount() + 1;
      if (cnt >= 5) {
        member.setStatus("INACTIVE");
      }
      member.setLoginFailCount(cnt);
      membersRepository.save(member);
      throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
    }

    // 3. 패스워드 실패 횟수 체크
    if (member.getLoginFailCount() >= 5) {
      throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
    }

    // 4. 인증 성공 로그인 시간 저장
    if (member.getFirstLoginDttm() == null) {
      member.setFirstLoginDttm(ZonedDateTime.now());
    }
    member.setLastLoginDttm(ZonedDateTime.now());
    member.setLoginFailCount(0);
    membersRepository.save(member);

    // 5. 인증 성공 → UserDetails 생성
    CustomUserDetails userDetails = new CustomUserDetails(member);

    return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
  }
}
