package com.dora.config;

import com.dora.entity.User;
import com.dora.service.JwtTokenManager;
import com.dora.service.UserService;
import com.dora.util.JwtUtil;
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.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

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

/**
 * JWT认证过滤器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserService userService;
    private final JwtTokenManager jwtTokenManager;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        // 添加调试日志
        String requestURI = request.getRequestURI();
        String userAgent = request.getHeader("User-Agent");
        String referer = request.getHeader("Referer");
        
        // 区分不同类型的根路径请求
        if ("/".equals(requestURI)) {
            if (userAgent != null && userAgent.contains("Mozilla")) {
                log.info("浏览器访问根路径: {} - {} (User-Agent: {}, Referer: {})", 
                    request.getMethod(), requestURI, 
                    userAgent.length() > 50 ? userAgent.substring(0, 50) + "..." : userAgent,
                    referer);
            } else {
                log.info("API/程序访问根路径: {} - {} (User-Agent: {})", 
                    request.getMethod(), requestURI, userAgent);
            }
        } else {
            log.debug("JWT拦截器处理请求: {} - {}", request.getMethod(), requestURI);
        }
        
        try {
            // 获取JWT令牌
            String token = getJwtFromRequest(request);
            
            // 验证令牌
            if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) {
                if (jwtUtil.isAdminToken(token)) {
                    handleAdminToken(token, request);
                } else if (jwtUtil.isUserToken(token)) {
                    Long userId = jwtUtil.getUserIdFromToken(token);
                    String jwtId = jwtUtil.getJwtIdFromToken(token);
                    
                    // 检查token是否在白名单中（设备数限制）
                    if (userId != null && jwtId != null && jwtTokenManager.isUserTokenValid(userId, jwtId)) {
                        if (!validateAndAuthenticateUser(userId, request, response, filterChain)) {
                            return; // 验证失败，已经处理完毕
                        }
                    } else {
                        log.warn("用户token不在白名单中或已失效 - userId: {}, jwtId: {}", userId, jwtId);
                        SecurityContextHolder.clearContext();
                    }
                }
            } else {
                // 对于没有有效JWT的请求，检查是否为允许匿名访问的路径
                if (isAnonymousAllowedPath(requestURI)) {
                    if ("/".equals(requestURI)) {
                        log.info("根路径匿名访问: {} - 将返回前端应用", request.getMethod(), requestURI);
                    } else {
                        log.debug("允许匿名访问的路径: {}", requestURI);
                    }
                    // 为匿名用户创建空的认证对象，避免后续认证失败
                    UsernamePasswordAuthenticationToken anonymousAuth = 
                        new UsernamePasswordAuthenticationToken("anonymous", null, new ArrayList<>());
                    SecurityContextHolder.getContext().setAuthentication(anonymousAuth);
                }
            }
        } catch (Exception e) {
            log.debug("JWT认证失败: {}", e.getMessage());
            // 即使JWT验证失败，对于允许匿名访问的路径也应该继续
            if (isAnonymousAllowedPath(requestURI)) {
                if ("/".equals(requestURI)) {
                    log.info("根路径JWT验证失败但允许匿名访问: {} - 将返回前端应用", requestURI);
                } else {
                    log.debug("JWT验证失败但允许匿名访问: {}", requestURI);
                }
                UsernamePasswordAuthenticationToken anonymousAuth = 
                    new UsernamePasswordAuthenticationToken("anonymous", null, new ArrayList<>());
                SecurityContextHolder.getContext().setAuthentication(anonymousAuth);
            }
        }
        
        filterChain.doFilter(request, response);
    }

    /**
     * 处理管理员token
     * @param token JWT token
     * @param request HTTP请求
     */
    private void handleAdminToken(String token, HttpServletRequest request) {
        Long adminId = jwtUtil.getAdminIdFromToken(token);
        Integer role = jwtUtil.getRoleFromToken(token);
        String jwtId = jwtUtil.getJwtIdFromToken(token);
        
        if (adminId != null && jwtId != null) {
            // 检查管理员token是否在白名单中
            if (jwtTokenManager.isAdminTokenValid(adminId, jwtId)) {
                // 为管理员创建认证对象，并赋予 ROLE_ADMIN 角色
                UsernamePasswordAuthenticationToken authentication = 
                    UsernamePasswordAuthenticationToken.authenticated(
                        adminId.toString(), 
                        null, 
                        Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"))
                    );
                
                // 设置认证信息到SecurityContext
                SecurityContextHolder.getContext().setAuthentication(authentication);
                // 兼容管理员控制器从request属性读取管理员ID和角色
                request.setAttribute("adminId", adminId.toString());
                request.setAttribute("adminRole", role);
                
                log.debug("管理员JWT认证成功，管理员ID: {}, 角色: ADMIN", adminId);
            } else {
                log.warn("管理员token不在白名单中或已失效 - adminId: {}, jwtId: {}", adminId, jwtId);
                SecurityContextHolder.clearContext();
            }
        }
    }

    /**
     * 验证用户并设置认证信息
     * @param userId 用户ID
     * @param request HTTP请求
     * @param response HTTP响应
     * @param filterChain 过滤器链
     * @return 是否验证成功
     */
    private boolean validateAndAuthenticateUser(Long userId, HttpServletRequest request, 
                                               HttpServletResponse response, FilterChain filterChain) 
                                               throws ServletException, IOException {
        try {
            // 从数据库查询用户信息
            User user = userService.getUserById(userId);
            if (user == null) {
                log.warn("用户已不存在，拒绝访问。用户ID: {}", userId);
                SecurityContextHolder.clearContext();
                filterChain.doFilter(request, response);
                return false;
            }
            
            // 检查用户是否被逻辑删除
            if (user.getIsDeleted() != null && user.getIsDeleted() == 1) {
                log.warn("用户已被删除，拒绝访问。用户ID: {}", userId);
                SecurityContextHolder.clearContext();
                filterChain.doFilter(request, response);
                return false;
            }
            
            // 通过所有验证，创建认证对象
            // 使用 authenticated() 方法创建已认证的 token，确保 isAuthenticated() 返回 true
            UsernamePasswordAuthenticationToken authentication = 
                UsernamePasswordAuthenticationToken.authenticated(
                    userId.toString(), 
                    null, 
                    Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
                );
            
            // 设置认证信息到SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // 兼容部分控制器从request属性读取用户ID
            request.setAttribute("userId", userId.toString());
            
            log.debug("用户JWT认证成功，用户ID: {}，用户名: {}", userId, user.getUsername());
            return true;
            
        } catch (Exception e) {
            log.error("验证用户存在性时发生错误，用户ID: {}, 错误: {}", userId, e.getMessage());
            // 发生异常时清除认证信息，拒绝访问
            SecurityContextHolder.clearContext();
            filterChain.doFilter(request, response);
            return false;
        }
    }

    /**
     * 检查是否为允许匿名访问的路径
     */
    private boolean isAnonymousAllowedPath(String requestURI) {
        return requestURI.startsWith("/user/course/") ||
               requestURI.startsWith("/user/workflow/") ||
               requestURI.startsWith("/user/auth/") ||
               requestURI.startsWith("/user/msm/") ||
               requestURI.startsWith("/user/oss/") ||
               requestURI.startsWith("/user/promotion/") ||
               requestURI.startsWith("/user/gift/") ||
               requestURI.startsWith("/user/pay/") ||
               requestURI.startsWith("/user/banner/") ||
               requestURI.startsWith("/user/v1/test/") ||
               requestURI.startsWith("/user/v1/external/") ||
               requestURI.startsWith("/user/v1/workflow-likes/") ||
               requestURI.startsWith("/user/v1/promotion-rules/") ||
               requestURI.startsWith("/admin/auth/") ||
               requestURI.startsWith("/swagger-ui/") ||
               requestURI.startsWith("/v3/api-docs/") ||
               requestURI.startsWith("/webjars/") ||
               requestURI.startsWith("/static/") ||
               requestURI.equals("/") ||
               requestURI.equals("/index.html") ||
               requestURI.endsWith(".html") ||
               requestURI.endsWith(".js") ||
               requestURI.endsWith(".css");
    }

    /**
     * 从请求中获取JWT令牌
     */
    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
} 