package com.style24.front.support.security;

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

import com.gagaframework.web.util.GagaCookieUtil;
import com.style24.front.support.exception.TsfNonCertificationAccountException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.env.TscConstants;
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.front.support.exception.TsfUsernameNotFoundException;
import com.style24.front.support.security.session.TsfSession;
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;

	@Value("${has-ssl}")
	private String hasSsl;

	private static final int LOGIN_FAIL_COUNT = 5; // 실패누적건수

	@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.setSnsId(GagaStringUtil.replace(loginId, TsfConstants.SNSLOGIN_PREFIX, ""));
			loginParam.setSnsType(passwd);
		} else { // 일반로그인
			loginParam.setCustId(loginId);
		}

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

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

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

		/// SNS로그인이 아닌 일반로그인 이면
		if (!loginId.startsWith(TsfConstants.SNSLOGIN_PREFIX)) {
			log.info("encoded password: {}", passwordEncoder.encodeSha256(passwd));
			boolean isMatch = passwordEncoder.matchesSha256(passwd, loginInfo.getPasswd());
			log.info("Password is match?: {}", isMatch);

			if (!isMatch) {
				throw new BadCredentialsException(message.getMessage("LOGN_0010"));
			}
		}

		// 휴면회원
		if (TscConstants.CustStat.DORMANT.value().equals(loginInfo.getCustStat())) {
			// 휴면해제를 위한 고객번호 세션저장
			TsfSession.setAttribute("custNo", String.valueOf(loginInfo.getCustNo()));
			throw new TsfDormantAccountException(message.getMessage("LOGN_0006"));
		}
		// 탈퇴회원
		if (TscConstants.CustStat.SECEDE.value().equals(loginInfo.getCustStat())) {
			throw new TsfSecedeAccountException(message.getMessage("LOGN_0007"));
		}
		// 활동회원 중 본인인증이 필요한 회원
//		2021.10.26 김유중 : ci 없는 회원이 본인 인증 시 실패가 많아서 로그인 처리로 변경(정지혜과장,전석훈차장 협의)
//		if (TscConstants.CustStat.ACTIVE.value().equals(loginInfo.getCustStat()) && StringUtils.isBlank(loginInfo.getCi())) {
//			TsfSession.setAttribute("custNo", String.valueOf(loginInfo.getCustNo()));
//			throw new TsfNonCertificationAccountException(message.getMessage("LOGN_0009"));
//		}

		// 권한 설정
		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));
	}

}
