package study.orderflow.config;

import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/// 资源服务器链（S01）：issuer/audience 固定为本实验本次注入值；
/// scope 转换保持默认 SCOPE_ 前缀。HS256 对称签名只用于合成实验，
/// 生产 RS 应用 AS 公钥（JWKS），不共享 secret。
@Configuration
@EnableMethodSecurity
// 安全过滤链只在 Servlet Web 应用有意义；web=NONE 的配置失败实验里不应因缺 HttpSecurity 抢先失败
@org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication(
        type = org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.SERVLET)
public class ResourceSecurityConfig {

    @Bean
    SecurityFilterChain orderChain(HttpSecurity http, JwtDecoder decoder) throws Exception {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        JwtGrantedAuthoritiesConverter scopes = new JwtGrantedAuthoritiesConverter();
        converter.setJwtGrantedAuthoritiesConverter(scopes);
        // 本 RS 只接受显式 Authorization: Bearer，没有浏览器自动携带的凭据，API 关闭 CSRF（与 U30 同一前提）；
        // Actuator 探针由平台 GET 调用，同样不依赖表单。这一前提不能推广成"无状态 API 都不需要 CSRF"。
        http.securityMatcher("/api/**", "/actuator/**")
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/actuator/health/liveness").permitAll()
                        .requestMatchers("/actuator/health/readiness").permitAll()
                        // U81：otelcol 以本地进程抓取 /actuator/prometheus；只放行该端点，
                        // 其余 actuator（env/heapdump 等）仍 denyAll
                        .requestMatchers("/actuator/prometheus").permitAll()
                        .requestMatchers("/api/**").hasAuthority("SCOPE_orders.write")
                        .anyRequest().denyAll())
                .oauth2ResourceServer(oauth -> oauth
                        .jwt(jwt -> jwt.decoder(decoder).jwtAuthenticationConverter(converter)));
        return http.build();
    }

    @Bean
    JwtDecoder jwtDecoder(
            @org.springframework.beans.factory.annotation.Value("${case.security.issuer}") String issuer,
            @org.springframework.beans.factory.annotation.Value("${case.security.audience}") String audience,
            @org.springframework.beans.factory.annotation.Value("${case.security.hs256-secret}") String secret) {
        SecretKey key = new SecretKeySpec(Base64.getDecoder().decode(secret), "HmacSHA256");
        NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(key).build();
        // createDefaultWithIssuer 只做 iss + 时间窗；audience 必须显式加校验器，否则给别的 API 签的 token 也能进来
        org.springframework.security.oauth2.core.OAuth2TokenValidator<org.springframework.security.oauth2.jwt.Jwt> validator =
                new org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator<>(
                        JwtValidators.createDefaultWithIssuer(issuer),
                        new org.springframework.security.oauth2.jwt.JwtClaimValidator<java.util.List<String>>(
                                "aud", aud -> aud != null && aud.contains(audience)));
        decoder.setJwtValidator(validator);
        return decoder;
    }
}
