package com.zsElectric.boot.security.filter;

import cn.hutool.core.util.StrUtil;
import com.zsElectric.boot.common.constant.SecurityConstants;
import com.zsElectric.boot.core.web.ResultCode;
import com.zsElectric.boot.core.web.WebResponseHelper;
import com.zsElectric.boot.security.token.TokenManager;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * Token 认证校验过滤器
 *
 * @author wangtao
 * @since 2025/3/6 16:50
 */
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    /**
     * Token 管理器
     */
    private final TokenManager tokenManager;

    public TokenAuthenticationFilter(TokenManager tokenManager) {
        this.tokenManager = tokenManager;
    }

    /**
     * 校验 Token ，包括验签和是否过期
     * 如果 Token 有效，将 Token 解析为 Authentication 对象，并设置到 Spring Security 上下文中
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String requestURI = request.getRequestURI();
        String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
        
        log.debug("[Token验证] 请求路径: {}, Authorization头: {}", requestURI, 
                authorizationHeader != null ? authorizationHeader.substring(0, Math.min(20, authorizationHeader.length())) + "..." : "无");

        try {
            if (StrUtil.isNotBlank(authorizationHeader)
                    && authorizationHeader.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX)) {

                // 剥离Bearer前缀获取原始令牌
                String rawToken = authorizationHeader.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
                log.debug("[Token验证] 开始验证token, 路径: {}", requestURI);

                // 执行令牌有效性检查（包含密码学验签和过期时间验证）
                boolean isValidToken = tokenManager.validateToken(rawToken);
                if (!isValidToken) {
                    log.warn("[Token验证失败] token无效或已过期, 路径: {}", requestURI);
                    WebResponseHelper.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
                    return;
                }

                // 将令牌解析为 Spring Security 上下文认证对象
                Authentication authentication = tokenManager.parseToken(rawToken);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                log.debug("[Token验证成功] 用户: {}, 路径: {}", authentication.getName(), requestURI);
            } else if (StrUtil.isNotBlank(authorizationHeader)) {
                log.warn("[Token格式错误] Authorization头不是以'Bearer '开头, 路径: {}, 头部内容: {}", 
                        requestURI, authorizationHeader.substring(0, Math.min(30, authorizationHeader.length())));
            }
        } catch (Exception ex) {
            // 安全上下文清除保障（防止上下文残留）
            log.error("[Token验证异常] 路径: {}, 错误: {}", requestURI, ex.getMessage(), ex);
            SecurityContextHolder.clearContext();
            WebResponseHelper.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
            return;
        }

        // 继续后续过滤器链执行
        filterChain.doFilter(request, response);
    }
}
