package com.dne.ems.security;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.dne.ems.service.JwtService;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

/**
 * JWT认证过滤器，处理每个请求的JWT认证
 *
 * <p>工作流程：
 * <ol>
 *   <li>从Authorization头提取JWT令牌</li>
 *   <li>验证令牌有效性</li>
 *   <li>加载用户详情</li>
 *   <li>设置安全上下文</li>
 * </ol>
 *
 * <p>安全特性：
 * <ul>
 *   <li>跳过认证相关路径(/api/auth)</li>
 *   <li>验证令牌签名和有效期</li>
 *   <li>不处理无效或过期的令牌</li>
 * </ul>
 *
 * @author DNE开发团队
 * @version 1.0
 * @since 2024-03
 * @see com.dne.ems.service.JwtService JWT服务
 * @see org.springframework.security.core.userdetails.UserDetailsService 用户详情服务
 */
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final JwtService jwtService;
    private final UserDetailsService userDetailsService;

    /**
     * 执行JWT认证过滤逻辑
     *
     * <p>处理步骤：
     * <ol>
     *   <li>检查请求路径是否需要跳过认证</li>
     *   <li>从Authorization头提取Bearer令牌</li>
     *   <li>验证令牌并提取用户名</li>
     *   <li>加载用户详情并设置认证上下文</li>
     * </ol>
     *
     * @param request HTTP请求
     * @param response HTTP响应
     * @param filterChain 过滤器链
     * @throws ServletException 如果发生servlet异常
     * @throws IOException 如果发生I/O异常
     */
    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
            throws ServletException, IOException {
        // 如果请求路径是认证相关的，则直接跳过此过滤器
        if (request.getServletPath().contains("/api/auth")) {
            filterChain.doFilter(request, response);
            return;
        }
        final String authHeader = request.getHeader("Authorization");
        final String jwt;
        final String userEmail;
        if (StringUtils.isEmpty(authHeader) || !StringUtils.startsWith(authHeader, "Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }
        jwt = authHeader.substring(7);
        userEmail = jwtService.extractUserName(jwt);
        if (StringUtils.isNotEmpty(userEmail)
                && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);
            if (jwtService.isTokenValid(jwt, userDetails)) {
                SecurityContext context = SecurityContextHolder.createEmptyContext();
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                context.setAuthentication(authToken);
                SecurityContextHolder.setContext(context);
            }
        }
        filterChain.doFilter(request, response);
    }
}