package com.yifu.cloud.plus.v1.yifu.auth.handler;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yifu.cloud.plus.v1.yifu.auth.constants.SecurityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.util.WebUtils;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.exception.InvalidException;
import com.yifu.cloud.plus.v1.yifu.common.security.util.AuthUtils;
import com.yifu.cloud.plus.v1.yifu.common.security.vo.UserAndToke;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MarkerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
 * @author fxj * @date 2022年05月30日 14:55 @description
 */
@Slf4j
@Builder
public class YifuWxLoginSuccessHandler implements AuthenticationSuccessHandler {
	private ObjectMapper objectMapper;
	private PasswordEncoder passwordEncoder;
	private ClientDetailsService clientDetailsService;
	private AuthorizationServerTokenServices defaultAuthorizationServerTokenServices;
	private TokenStore tokenStore;
	private final CacheManager cacheManager;
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

		/*String header = request.getHeader(SecurityConstants.CLIENT_HEADER_KEY_NEW);
		if(Common.isEmpty(header)){
			header = request.getHeader(SecurityConstants.CLIENT_HEADER_KEY);
			//兼容老逻辑
			if(Common.isEmpty(header)){
				header = request.getHeader(HttpHeaders.AUTHORIZATION);
			}
		}*/
		YifuUser user = null;
		try {
			user = (YifuUser)authentication.getPrincipal();
			/*if (header == null) {
				throw new InvalidClientException("请求头中client信息为空");
			}
			String[] tokens = AuthUtils.extractAndDecodeHeader(header);
			assert tokens.length == 2;
			String clientId = tokens[0];

			ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);

			//校验secret
			if (!passwordEncoder.matches(tokens[1], clientDetails.getClientSecret())) {
				throw new InvalidClientException("请求头中client信息验证异常");
			}*/
			//TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, clientDetails.getScope(), "password");
			Collection<String> scope = new ArrayList<>();
			scope.add("server");
			TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), "auth",scope, "password");
			//校验scope
			ClientDetails clientDetails = clientDetailsService.loadClientByClientId("auth");
			new DefaultOAuth2RequestValidator().validateScope(tokenRequest, clientDetails);
			OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
			OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
			OAuth2AccessToken oAuth2AccessToken = null;
			oAuth2AccessToken = defaultAuthorizationServerTokenServices.getAccessToken(oAuth2Authentication);
			if(null == oAuth2AccessToken){
				oAuth2AccessToken = defaultAuthorizationServerTokenServices.createAccessToken(oAuth2Authentication);
			}else{
				Map<String, Object> additionalInformation = clientDetails.getAdditionalInformation();
				if(null != additionalInformation && null != additionalInformation.get(SecurityConstants.MUTUALLY_EXCLUSIVE_LOGIN)){
					//单点刷新老的token生成新token
					tokenStore.removeAccessToken(oAuth2AccessToken);
					oAuth2AccessToken = defaultAuthorizationServerTokenServices.createAccessToken(oAuth2Authentication);
				}
			}
			log.info("获取token 成功：{}", oAuth2AccessToken.getValue());
			R<UserAndToke> result = new R<>(new UserAndToke(oAuth2AccessToken,user));

			backResult(response, result);
		} catch (Exception e) {
			if (e instanceof InvalidException){
				throw (InvalidException)e ;
			}else if(e instanceof InvalidClientException){
				String ip = WebUtils.getIP(request);
				if( null != ip && !ip.startsWith("127") && !ip.startsWith("192.168")){
					log.error(MarkerFactory.getMarker("MAIL"),"{}({})登录错误(触发黑名单逻辑)ip:{},头部信息为：{}",null==user?"":user.getUsername(),null==user?"":user.getUsername(),ip, JSONObject.toJSON(WebUtils.getHeadersInfo(request)));
				}else{
					log.error(MarkerFactory.getMarker("MAIL"),"{}({})登录错误ip:{},头部信息为：{}",null==user?"":user.getUsername(),null==user?"":user.getUsername(),ip, JSONObject.toJSON(WebUtils.getHeadersInfo(request)));
				}
				throw (InvalidClientException)e;
			}else{
				log.error(MarkerFactory.getMarker("MAIL"),"{}({})登录错误ip:{},头部信息为：{}",null==user?"":user.getUsername(),null==user?"":user.getUsername(),WebUtils.getIP(request), JSONObject.toJSON(WebUtils.getHeadersInfo(request)));
				throw new InvalidException("未知异常请联系管理员！",e);
			}
		}
	}

	private void backResult(HttpServletResponse response, R result) throws IOException {
		response.setCharacterEncoding(CharsetUtil.UTF_8);
		response.setContentType(CommonConstants.CONTENT_TYPE);
		response.setStatus(HttpStatus.HTTP_OK);
		PrintWriter printWriter = response.getWriter();
		printWriter.append(objectMapper.writeValueAsString(result));
	}

}
