package org.ta.gateway.config;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import jakarta.annotation.Resource;
import java.nio.charset.StandardCharsets;

@Component
public class AuthServerTokenFilter implements GlobalFilter, Ordered {

    @Resource
    private ReactiveJwtDecoder reactiveJwtDecoder;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getPath().value();

        // 跳过 Auth-Server 授权相关路径（无需校验令牌）
        if (path.startsWith("/oauth2/") || path.equals("/login.html") || path.equals("/login")
                || path.equals("/oauth2/consent") || path.equals("/callback")) {
            return chain.filter(exchange);
        }

        // 仅校验 /api/** 业务请求的令牌
        if (path.startsWith("/api/")) {
            String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                return writeErrorResponse(response, HttpStatus.UNAUTHORIZED,
                        "缺失有效令牌：Authorization 头格式应为 Bearer {token}");
            }

            String token = authHeader.substring(7);
            // 解码器自动验证：签名 + 算法 + 签发者 + 过期时间（含时钟偏差）
            return reactiveJwtDecoder.decode(token)
                    .flatMap(jwt -> {
                        // 透传 Auth-Server 令牌中的用户信息到业务服务
                        ServerHttpRequest modifiedRequest = request.mutate()
                                .header("X-User-Name", jwt.getSubject())
                                .header("X-User-Scope", String.join(",", jwt.getClaimAsStringList("scope")))
                                .header("X-Token-Issuer", String.valueOf(jwt.getIssuer()))
                                .build();
                        return chain.filter(exchange.mutate().request(modifiedRequest).build());
                    })
                    .onErrorResume(e -> writeErrorResponse(response, HttpStatus.UNAUTHORIZED,
                            "令牌无效/过期：" + e.getMessage()));
        }

        // 其他路径直接转发
        return chain.filter(exchange);
    }

    /**
     * 统一 JSON 错误响应（适配前端解析）
     */
    private Mono<Void> writeErrorResponse(ServerHttpResponse response, HttpStatus status, String message) {
        response.setStatusCode(status);
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
        String errorJson = String.format(
                "{\"code\":%d,\"success\":false,\"message\":\"%s\",\"timestamp\":\"%d\"}",
                status.value(),
                message,
                System.currentTimeMillis()
        );
        return response.writeWith(Mono.just(
                response.bufferFactory().wrap(errorJson.getBytes(StandardCharsets.UTF_8))
        ));
    }

    /**
     * 过滤器优先级：确保令牌校验在路由转发前执行
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 10;
    }
}