package com.test.bijihoudaun.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.bijihoudaun.common.response.R;
import com.test.bijihoudaun.common.response.ResultCode;
import com.test.bijihoudaun.util.JwtTokenUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    private final String tokenHeader;
    private final String tokenHead;

    public JwtAuthenticationTokenFilter(UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, String tokenHeader, String tokenHead) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.tokenHeader = tokenHeader;
        this.tokenHead = tokenHead;
    }

/**
 * 内部过滤器方法，用于处理请求的认证逻辑
 * @param request HttpServletRequest对象，包含请求信息
 * @param response HttpServletResponse对象，用于响应
 * @param chain FilterChain过滤器链，用于传递请求和响应
 * @throws ServletException 可能抛出的Servlet异常
 * @throws IOException 可能抛出的IO异常
 */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
    // 从请求头中获取认证信息
        String authHeader = request.getHeader(this.tokenHeader);
    // 修复：添加 tokenHead 空值检查
        if (authHeader != null && this.tokenHead != null && authHeader.startsWith(this.tokenHead)) {
        // 提取实际的token值（去除前缀）
            final String authToken = authHeader.substring(this.tokenHead.length());
            try {
            // 从token中解析出用户名
                String username = jwtTokenUtil.getUsernameFromToken(authToken);

            // 验证用户名不为空且当前没有已认证的用户
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                // 通过用户名加载用户详情
                    UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

                // 验证token的有效性
                    if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    // 创建认证对象
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    // 设置认证详情
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    // 将认证信息存入安全上下文
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            } catch (ExpiredJwtException e) {
            // 处理token过期异常
                sendErrorResponse(response, ResultCode.TOKEN_EXPIRED);
                return;
            } catch (SignatureException e) {
            // 处理token签名异常
                sendErrorResponse(response, ResultCode.TOKEN_INVALID);
                return;
            } catch (JwtException e) {
            // 修复：捕获所有JWT异常作为兜底
                sendErrorResponse(response, ResultCode.TOKEN_INVALID);
                return;
            }
        }
    // 继续过滤器链的处理
        chain.doFilter(request, response);
    }

/**
 * 发送错误响应信息
 * @param response HTTP响应对象
 * @param resultCode 结果代码，包含错误信息
 * @throws IOException 可能抛出的IO异常
 */
    private void sendErrorResponse(HttpServletResponse response, ResultCode resultCode) throws IOException {
    // 设置响应内容类型为JSON，字符编码为UTF-8
        response.setContentType("application/json;charset=UTF-8");
    // 设置HTTP状态码为401未授权
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    // 修复：使用 try-with-resources 确保 PrintWriter 关闭
        try (PrintWriter writer = response.getWriter()) {
            // 创建ObjectMapper实例，用于对象与JSON之间的转换
            ObjectMapper mapper = new ObjectMapper();
            // 将失败结果转换为JSON字符串并写入响应输出流
            writer.write(mapper.writeValueAsString(R.fail(resultCode)));
            writer.flush();
        }
    }
}
