package com.style24.scm.support.security;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import com.style24.core.support.message.TscMessageByLocale;
import com.style24.persistence.domain.User;
import com.style24.scm.biz.service.TssLoginService;
import com.style24.scm.support.security.session.TssSession;

import lombok.extern.slf4j.Slf4j;

import com.gagaframework.web.security.GagaPasswordEncoder;
import com.gagaframework.web.util.GagaCryptoUtil;

/**
 * 로그인 인증 처리
 * 
 * @author gagamel
 * @since 2020. 10. 19
 */
@Component
@Slf4j
public class TssAuthenticationProvider implements AuthenticationProvider {

	@Autowired
	private TssLoginService loginService;

	@Autowired
	private TscMessageByLocale message;

	@Autowired
	private GagaPasswordEncoder passwordEncoder;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		String userId = authentication.getName();
		String passwd = authentication.getCredentials().toString();
		log.info("userId: {}, passwd: {}", userId, passwd);

		// 로그인 정보
		User loginInfo = loginService.getUserById(authentication.getName());
		log.info("loginInfo: {}", loginInfo);

		if (loginInfo == null) {
			log.error(String.format("User with ID=%s was not found!", userId));
			throw new BadCredentialsException(message.getMessage("LOGN_0001"));
		}

		// 로그인 실패누적건수가 5이면
		if (loginInfo.getLoginFailCnt() == 5) {
			throw new BadCredentialsException(message.getMessage("LOGN_0005"));
		}

		log.info("encoded password: {}", GagaCryptoUtil.encryptSha512(passwd));
		boolean isMatch = passwordEncoder.matches(passwd, loginInfo.getPasswd());
		log.info("isMatch: {}", isMatch);

		if (!isMatch) {
			// 로그인 실패 남기기
			loginService.createLoginFail(loginInfo.getUserNo(), "Y");
			throw new BadCredentialsException(message.getMessage("LOGN_0002"));
		}

		// IP주소 체크
		if (!matchIpAddress(loginInfo.getIpChkYn(), loginInfo.getIpAddr())) {
			throw new BadCredentialsException(message.getMessage("LOGN_0005"));
		}

		// 권한 설정
		List<SimpleGrantedAuthority> authorities = new ArrayList<>();
		authorities.add(new SimpleGrantedAuthority(loginInfo.getRoleCd()));

		// 인증 토큰 생성
		UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
			loginInfo.getUserId(), loginInfo.getPasswd(), authorities);
		authToken.setDetails(new TssLoginDetails(loginInfo, authorities));

		return authToken;
	}

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

	/**
	 * IP주소 체크
	 * @param ipChkYn - IP주소체크여부
	 * @param loginIpAddr - 로그인IP주소
	 * @return
	 */
	private boolean matchIpAddress(String ipChkYn, String loginIpAddr) {
		String requestIpAddr = TssSession.getIpAddress();

		log.info("ipChkYn: {}, request ip address: {} vs user's ip address: {}", ipChkYn, requestIpAddr, loginIpAddr);

		if (ipChkYn.equals("N")) {
			return true;
		}

		if (!StringUtils.isNotBlank(loginIpAddr)) {
			return true;
		}

		if (!loginIpAddr.equals(requestIpAddr)) {
			return false;
		}

		return true;
	}

}
