package com.kxs.common.security.support.refresh;

import com.kxs.common.core.constant.SecurityConstants;
import com.kxs.common.security.util.OAuth2EndpointUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author LXQ
 * @date 2024-06-02
 *
 * 刷新token转换器
 */
public class OAuth2ResourceOwnerRefreshAuthenticationConverter  implements AuthenticationConverter {

	@Override
	public Authentication convert(HttpServletRequest request) {
		String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
		if (!AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(grantType)) {
			return null;
		} else {
			Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
			MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
			String refreshToken = parameters.getFirst(OAuth2ParameterNames.REFRESH_TOKEN);
			if (!StringUtils.hasText(refreshToken) || parameters.get(OAuth2ParameterNames.REFRESH_TOKEN).size() != 1) {
				OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REFRESH_TOKEN, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
			}

			String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
			if (StringUtils.hasText(scope) && parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
				OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.SCOPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
			}

			Set<String> requestedScopes = null;
			if (StringUtils.hasText(scope)) {
				requestedScopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
			}

			Map<String, Object> additionalParameters = new HashMap<>();
			parameters.forEach((key, value) -> {
				if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) && !key.equals(OAuth2ParameterNames.REFRESH_TOKEN) && !key.equals(OAuth2ParameterNames.SCOPE)) {
					additionalParameters.put(key, value.size() == 1 ? value.get(0) : value.toArray(new String[0]));
				}

			});
			return new OAuth2RefreshTokenAuthenticationToken(refreshToken, clientPrincipal, requestedScopes, additionalParameters);
		}
	}
}
