package org.lingniu.idp.security.filter;

import org.lingniu.idp.model.vo.AccessTokenInfo;
import org.lingniu.idp.service.core.login.IdpTokenService;
import org.lingniu.idp.service.core.login.RedisAccessTokenService;
import org.springframework.core.log.LogMessage;
import org.springframework.http.HttpMethod;
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.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
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;

public class IdpAuthenticationFilter extends OncePerRequestFilter {
    private static final RequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = PathPatternRequestMatcher.withDefaults()
            .matcher(HttpMethod.POST, "/oauth2/authorize");
    private final IdpTokenService idpTokenService;
    private final UserDetailsService userDetailsService;
    
    public IdpAuthenticationFilter(IdpTokenService idpTokenService, UserDetailsService userDetailsService) {
        this.idpTokenService = idpTokenService;
        this.userDetailsService = userDetailsService;
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {
        if (!requiresAuthentication(request, response)) {
            filterChain.doFilter(request, response);
            return;
        }
        
        try {
            AccessTokenInfo accessTokenInfo = null;
            // 验证令牌
            if (idpTokenService.validateAccessToken(request)) {
                accessTokenInfo = idpTokenService.getAccessTokenInfo(request);
            }else{
                accessTokenInfo = idpTokenService.refreshToken(request, response);
            }
            if(accessTokenInfo!=null){
                // 加载用户详情
                UserDetails userDetails = userDetailsService.loadUserByUsername(accessTokenInfo.getUsername());
                // 创建认证对象
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(
                                userDetails,
                                null,
                                null
                        );

                // 设置认证信息到SecurityContext
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }

        } catch (Exception e) {
            // 令牌验证失败，记录日志但不中断请求
            logger.error("token 验证失败", e);
        }
        
        filterChain.doFilter(request, response);
    }
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        if (DEFAULT_ANT_PATH_REQUEST_MATCHER.matches(request)) {
            return true;
        }
        if (this.logger.isTraceEnabled()) {
            this.logger
                    .trace(LogMessage.format("Did not match request to %s", DEFAULT_ANT_PATH_REQUEST_MATCHER));
        }
        return false;
    }

}