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.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
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.Map;

/**
 * @author fxj * @date 2022年05月30日 14:55 @description
 */
@Slf4j
@Builder
public class YifuClientLoginSuccessHandler 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];
			/*boolean noThisClientId = true;
			if (null != user.getOrganClientId()){
				for(String id :user.getOrganClientId()){//验证单位权限
					if(id.equals(clientId)){
						noThisClientId = false;
						break;
					}
				}
			} else {
				throw new InvalidException("所属终端为空!");

			}*/
			/*if (null != user.getClientRoleMap()){//验证角色
				List<Long> thisClientRoleList = user.getClientRoleMap().get(clientId);
				if(null == thisClientRoleList){
					if(null != ServiceNameConstants.CLIENT_NAME_MAP.get(clientId)){
						clientId = ServiceNameConstants.CLIENT_NAME_MAP.get(clientId);
					}
					throw new InvalidException(user.getNickname()+"没有\""+ clientId +"\"的角色!请联系管理员分配角色！");
				}else{
					if (null != user.getAuthorities()){//剔除非登录终端的权限（权限只能重建，不能修改）
						final String finalClientId = clientId;
						// 构造security用户
						ExtendUser thisUser = new ExtendUser(user.getId(), user.getDeptId(), user.getUsername(),  " ",
								user.getNickName(), user.getOrganId(),user.getDepartCode(), user.getDbKey(), user.getOrganClientId(), user.getOrganLevel(), user.isAccountNonLocked(), true, true, true, user.getAuthorities().stream().filter(auth-> { String[] authStr = String.valueOf(auth).split(":"); return authStr.length<1 || finalClientId.equals(authStr[0]);}).collect(Collectors.toSet()));
						thisUser.setClientRoleMap(user.getClientRoleMap());
						thisUser.setRoleDataLevelMap(user.getRoleDataLevelMap());
						thisUser.setSettleIdList(user.getSettleIdList());
						thisUser.setAvatar(user.getAvatar());
						user = thisUser;
					}
				}
			} else {
				throw new InvalidException(user.getUsername()+"没有角色！");
			}*/

			/*if(noThisClientId){
				if(null != ServiceNameConstants.CLIENT_NAME_MAP.get(clientId)){
					clientId = ServiceNameConstants.CLIENT_NAME_MAP.get(clientId);
				}
				throw new InvalidException("该机构没有\""+ clientId +"\"服务权限！请联系管理员开通！");
			}*/
			//非管理员获取 b端项目权限
			/*if(ServiceNameConstants.CLIENT_ID_HR_B.equals(clientId) && !SecurityUtils.isHaveAllOrg(clientId,user)){
				if(Common.isEmpty(user.getSettleIdList())){
					throw new InvalidException("该用户("+user.getNickName()+")没有项目权限！请联系管理员开通！")
				}
			}*/

			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");
			//校验scope
			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));
	}

}
