package com.auth.module.security.config;


import com.auth.module.security.config.properties.SecurityConfigProperties;
import com.auth.module.security.filter.JwtAuthenticationFilter;
import com.auth.module.security.handler.SecurityAccessDeniedHandler;
import com.auth.module.security.handler.SecurityAuthenticationEntryPoint;
import lombok.RequiredArgsConstructor;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true)
@RequiredArgsConstructor
public class SecurityWebConfiguration {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final SecurityConfigProperties pathsProperties;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                // 前端段分离不需要---禁用明文验证
                // .httpBasic(AbstractHttpConfigurer::disable)
                // 前端段分离不需要---禁用默认登录页
                .formLogin(AbstractHttpConfigurer::disable)
                // 前端段分离不需要---禁用退出页
                .logout(AbstractHttpConfigurer::disable)
                // 前端段分离不需要---csrf攻击
                .csrf(AbstractHttpConfigurer::disable)
                // 跨域访问权限，如果需要可以关闭后自己配置跨域访问
                .cors(AbstractHttpConfigurer::disable)
                // 前后端分离不需要---因为是无状态的
                // .sessionManagement(AbstractHttpConfigurer::disable)
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                // 如果要对部分接口做登录校验 或者 项目中需要使用粗粒度的 校验
                .authorizeHttpRequests(authorizeRequests ->
                        // 访问路径为 /api 时需要进行认证
                        authorizeRequests
                                // 不认证登录接口
                                .requestMatchers(pathsProperties.noAuthPaths.toArray(String[]::new)).permitAll()
                                // ❗安全路径配置说明❗
                                // =======================================================================
                                // 主要功能：配置需要认证的接口路径（支持多个参数，如："/api/**","/admin/**"）
                                //
                                // 注意事项：
                                // 1. 此处配置会覆盖方法级的@PermitAll注解
                                // 2. 如需"携带token则验证，否则放行"的动态效果，不可用此方式配置
                                //    - 原因：配置为authenticated()则必须登录
                                //    - 若配置为permitAll()则无法自动注入SecurityContext
                                //
                                // 最佳实践建议：
                                // 1. 固定需要强制认证的路径可在此配置（如：pathsProperties.securedPaths）
                                // 2. 动态路径建议：
                                //    - 方案A：存储在数据库+自定义过滤器实现
                                //    - 方案B：使用方法级权限控制（@PreAuthorize等）
                                //
                                // 示例配置（当前项目）：
                                // .requestMatchers(pathsProperties.securedPaths.toArray(String[]::new)).authenticated()
                                // =======================================================================
                                // 其余请求都放行
                                .anyRequest().permitAll()
                )
                .exceptionHandling(exception -> {
                    // 请求未授权接口
                    exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
                    // 没有权限访问
                    exception.accessDeniedHandler(new SecurityAccessDeniedHandler());
                })
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
        ;

        return http.build();
    }
}