package org.dromara.member.config;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.member.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * JWT过滤器
 *
 * @author pengles
 */
@Component
@RequiredArgsConstructor
public class AppJwtFilter extends OncePerRequestFilter {

    @Value("${ruoyi.app.jwt.secret:ruoyi-secret}")
    private String jwtSecret;
    private static final String BLACKLIST_PREFIX = "APP:JWT:BLACKLIST:";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String path = request.getRequestURI();
        // 仅保护敏感接口
        if (requiresAuth(path)) {
            String auth = request.getHeader("Authorization");
            if (auth == null || !auth.startsWith("Bearer ")) {
                write401(response);
                return;
            }
            String token = auth.substring("Bearer ".length()).trim();
            JwtUtil jwt = new JwtUtil(jwtSecret);
            if (!jwt.verify(token)) {
                write401(response);
                return;
            }
            Map<String, Object> payload = jwt.parsePayload(token);
            Object expObj = payload.get("exp");
            long now = java.time.Instant.now().getEpochSecond();
            long exp = expObj instanceof Number ? ((Number) expObj).longValue() : now;
            if (exp < now) {
                write401(response);
                return;
            }
            String jti = String.valueOf(payload.get("jti"));
            String bl = RedisUtils.getCacheObject(BLACKLIST_PREFIX + jti);
            if (bl != null) {
                write401(response);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    private boolean requiresAuth(String path) {
        if (path == null) return false;
        // 保护系统会话/消息/用户/文件等接口
        return path.startsWith("/system/session")
                || path.startsWith("/system/message")
                || path.startsWith("/app/user")
                || path.startsWith("/app/file");
    }

    private void write401(HttpServletResponse response) throws IOException {
        response.setStatus(401);
        response.setContentType("application/json");
        response.getOutputStream().write("{\"code\":401,\"msg\":\"Unauthorized\",\"data\":null}".getBytes(StandardCharsets.UTF_8));
    }
}

