package org.xyzh.common.auth.annotation.resovler;

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.xyzh.common.auth.annotation.HttpLogin;
import org.xyzh.common.auth.token.TokenParser;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.common.utils.NonUtils;

import jakarta.servlet.http.HttpServletRequest;

/**
 * @description    HttpLoginArgumentResolver.java文件描述 HTTP登录参数解析器
 * @filename    HttpLoginArgumentResolver.java
 * @author    yslg
 * @copyright yslg
 * @since 2025-11-02
 */
@Component
public class HttpLoginArgumentResolver implements HandlerMethodArgumentResolver  {
    
    private final TokenParser tokenParser;
    private final RedisService redisService;

    /**
     * 使用构造器注入，依赖TokenParser接口而非具体实现
     * 这样避免了与auth模块的直接依赖，解决循环依赖问题
     */
    public HttpLoginArgumentResolver(TokenParser tokenParser, 
                                     RedisService redisService) {
        this.tokenParser = tokenParser;
        this.redisService = redisService;
    }

    private static final String TOKEN_PREFIX = "Bearer ";
    private static final String REDIS_LOGIN_PREFIX = "login:token:";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(HttpLogin.class) 
               && LoginDomain.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        
        HttpLogin httpLogin = parameter.getParameterAnnotation(HttpLogin.class);
        if (httpLogin == null) {
            return null;
        }

        // 从请求头中获取token
        String token = extractTokenFromRequest(webRequest);
        
        if (NonUtils.isEmpty(token)) {
            if (httpLogin.required()) {
                throw new IllegalArgumentException(httpLogin.message());
            }
            return null;
        }

        try {
            // 验证token格式和有效性
            if (!tokenParser.validateToken(token, tokenParser.getUserIdFromToken(token))) {
                if (httpLogin.required()) {
                    throw new IllegalArgumentException(httpLogin.message());
                }
                return null;
            }

            // 从Redis中获取LoginDomain
            String userId = tokenParser.getUserIdFromToken(token);
            String redisKey = REDIS_LOGIN_PREFIX + userId;
            LoginDomain loginDomain = redisService.get(redisKey, LoginDomain.class);

            if (loginDomain == null) {
                if (httpLogin.required()) {
                    throw new IllegalArgumentException(httpLogin.message());
                }
                return null;
            }

            // 更新token信息
            loginDomain.setToken(token);
            return loginDomain;

        } catch (Exception e) {
            if (httpLogin.required()) {
                throw new IllegalArgumentException(httpLogin.message());
            }
            return null;
        }
    }

    /**
     * @description    从请求中提取token
     * @param    webRequest 请求对象
     * @return    String token
     * @author    yslg
     * @since 2025-11-02
     */
    private String extractTokenFromRequest(NativeWebRequest webRequest) {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request == null) {
            return null;
        }

        // 优先从Authorization头获取
        String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (NonUtils.isNotEmpty(authHeader) && authHeader.startsWith(TOKEN_PREFIX)) {
            return authHeader.substring(TOKEN_PREFIX.length());
        }

        // 从请求参数中获取token
        String token = request.getParameter("token");
        if (NonUtils.isNotEmpty(token)) {
            return token;
        }

        // 从请求头中获取token
        token = request.getHeader("token");
        if (NonUtils.isNotEmpty(token)) {
            return token;
        }

        return null;
    }
}
