package com.hys.app.oauth2.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.hys.app.framework.exception.ErrorMessage;
import com.hys.app.framework.exception.ServiceException;
import com.hys.app.framework.util.JsonUtil;
import com.hys.app.model.oauth2.dos.OAuth2AccessTokenDO;
import com.hys.app.model.oauth2.dto.LoginClient;
import com.hys.app.oauth2.LoginClientHolder;
import com.hys.app.oauth2.utils.OAuth2Utils;
import com.hys.app.service.oauth2.OAuth2TokenManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * OAuth2 Token 过滤器，验证 token 的有效性，目前只用于三方接口认证
 * 验证通过后，获得 {@link LoginClient} 信息，并加入到线程上下文
 *
 * @author 张崧
 * @since 2024-02-21
 */
@WebFilter(filterName = "oAuth2AuthenticationFilter", urlPatterns = "/open/*")
public class OAuth2AuthenticationFilter extends OncePerRequestFilter {

    /**
     * HTTP 请求时，访问令牌的请求 Header
     */
    private static final String TOKEN_HEADER = "Authorization";
    /**
     * HTTP 请求时，访问令牌的请求参数
     */
    private static final String TOKEN_PARAMETER = "token";

    @Autowired
    private OAuth2TokenManager oAuth2TokenManager;

    @Override
    @SuppressWarnings("NullableProblems")
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        try {
            // 1. 请求中获取token
            String token = OAuth2Utils.obtainAuthorization(request, TOKEN_HEADER, TOKEN_PARAMETER);
            if (StrUtil.isEmpty(token)) {
                throw new ServiceException("token未传递");
            }
            // 2. 基于 token 构建登录客户端
            LoginClient loginClient = buildLoginClientByToken(token);

            // 3. 设置当前登录客户端
            LoginClientHolder.set(loginClient);

            // 继续过滤链
            chain.doFilter(request, response);
        } catch (Exception e) {
            writeErrorJson(response, e);
        }
    }

    @Override
    public void destroy() {
        LoginClientHolder.remove();
    }

    private void writeErrorJson(HttpServletResponse response, Exception e) {
        ErrorMessage errorMessage = new ErrorMessage();
        errorMessage.setMessage(e.getMessage());
        errorMessage.setCode("403");
        ServletUtil.write(response, JsonUtil.objectToJson(errorMessage), MediaType.APPLICATION_JSON_UTF8_VALUE);
    }

    private LoginClient buildLoginClientByToken(String token) {
        OAuth2AccessTokenDO accessToken = oAuth2TokenManager.checkAccessToken(token);
        // 构建登录用户
        return new LoginClient().setClientId(accessToken.getClientId());
    }

}
