package com.style24.front.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.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import com.style24.core.support.message.TscMessageByLocale;
import com.style24.front.biz.service.TsfLoginService;
import com.style24.front.support.env.TsfConstants;
import com.style24.front.support.exception.TsfDormantAccountException;
import com.style24.front.support.exception.TsfEmailDuplicationException;
import com.style24.front.support.exception.TsfLockedAccountException;
import com.style24.front.support.exception.TsfSecedeAccountException;
import com.style24.persistence.domain.Login;

import lombok.extern.slf4j.Slf4j;

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

/**
 * 로그인 인증 처리
 * 
 * @author gagamel
 * @since 2020. 9. 11
 */
@Component
@Slf4j
public class TsfAuthenticationProvider implements AuthenticationProvider {

	@Autowired
	private TsfLoginService loginService;

	@Autowired
	private TscMessageByLocale message;

	@Autowired
	private GagaPasswordEncoder passwordEncoder;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		String loginId = authentication.getName();

		// 일반로그인일 때는 비밀번호이고 SNS로그인일 때는 이메일 정보임
		String passwd = authentication.getCredentials().toString();
		log.info("loginId: {}, passwd: {}", loginId, passwd);

		// 로그인 정보
		Login loginParam = new Login();

		// SNS로그인이면
		if (loginId.startsWith(TsfConstants.SNSLOGIN_PREFIX)) {
			loginParam.setCustId(GagaStringUtil.replace(loginId, TsfConstants.SNSLOGIN_PREFIX, ""));
			loginParam.setSnsType(loginId.substring(loginId.indexOf("-", 0) + 1, loginId.lastIndexOf("-") - 1));
			loginParam.setEmail(passwd); // SNS로그인이면 이메일 정보
		} else { // 일반로그인
			loginParam.setCustId(loginId);
		}

		// 로그인정보 조회
		Login loginInfo = loginService.getLoginCheckInfo(loginParam);
		log.debug("loginInfo: {}", loginInfo);

		if (loginInfo == null) {
			log.debug(String.format("Customer with ID=%s was not found!", loginId));
			throw new UsernameNotFoundException(message.getMessage("LOGN_0001"));
		}

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

		/// SNS로그인이 아닌 일반로그인 이면
		if (!loginId.startsWith(TsfConstants.SNSLOGIN_PREFIX)) {
			log.debug("encoded pwd: {}", passwordEncoder.encode(passwd));
			boolean isMatch = passwordEncoder.matches(passwd, loginInfo.getPasswd());
			log.debug("isMatch: {}", isMatch);

			if (!isMatch) {
//				// 로그인 실패 남기기
//				customerService.createLoginFail(loginInfo.getCustId(), "Y");
				throw new BadCredentialsException(message.getMessage("LOGN_0002"));
			}
		} else {
			// SNS로그인 시 로그인ID 값은 이메일로 처리했으므로
			// loginId 값과 회원정보의 이메일 값을 비교해서 동일하면
			if (StringUtils.isBlank(loginInfo.getSnsType()) && passwd.equals(loginInfo.getEmail())) {
				throw new TsfEmailDuplicationException(message.getMessage("LOGN_0008"));
			}
		}

		if (loginInfo.getCustStat().equals("20")) { // 휴면회원
//			WfoSession.setDormantMemberNo(request, loginInfo.getCustId());
			throw new TsfDormantAccountException(message.getMessage("LOGN_0006"));
		} else if (loginInfo.getCustStat().equals("30")) { // 탈퇴회원
			throw new TsfSecedeAccountException(message.getMessage("LOGN_0007"));
		}

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

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

		return authToken;
	}

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

}
