package cn.meowrain.aioj.backend.framework.security.filter;

import cn.meowrain.aioj.backend.framework.security.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

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

/**
 * JWT 认证过滤器
 * 拦截所有请求，验证 JWT Token 并设置 SecurityContext
 */
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

	private final JwtUtil jwtUtil;

	private static final String TOKEN_PREFIX = "Bearer ";

	private static final String HEADER_NAME = "Authorization";

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		try {
			String token = extractTokenFromRequest(request);

			if (StringUtils.hasText(token) && jwtUtil.isTokenValid(token)) {
				Claims claims = jwtUtil.parseClaims(token);
				Authentication authentication = createAuthentication(claims);
				SecurityContextHolder.getContext().setAuthentication(authentication);

				log.debug("JWT Authentication successful for user: {}", claims.getSubject());
			}
			else {
				log.debug("No valid JWT token found in request");
			}
		}
		catch (Exception e) {
			log.error("JWT Authentication failed", e);
			SecurityContextHolder.clearContext();
		}

		filterChain.doFilter(request, response);
	}

	/**
	 * 从请求中提取 JWT Token
	 */
	private String extractTokenFromRequest(HttpServletRequest request) {
		String bearerToken = request.getHeader(HEADER_NAME);
		if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
			return bearerToken.substring(TOKEN_PREFIX.length());
		}
		return null;
	}

	/**
	 * 根据 JWT Claims 创建 Authentication 对象
	 */
	private Authentication createAuthentication(Claims claims) {
		String userId = claims.getSubject();
		String role = claims.get("role", String.class);

		// 创建权限列表
		List<SimpleGrantedAuthority> authorities = Collections
			.singletonList(new SimpleGrantedAuthority("ROLE_" + (role != null ? role : "USER")));

		// 创建认证对象（principal 为 userId 字符串）
		UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userId, null,
				authorities);

		return authentication;
	}

	@Override
	protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
		String path = request.getRequestURI();
		// 跳过不需要 JWT 验证的路径
		// 子类可以通过重写此方法来自定义白名单
		return path.startsWith("/v3/api-docs") || path.equals("/favicon.ico") || path.contains("/swagger");
	}

}
