package com.backendsys.modules.common.config.security;

import cn.hutool.core.util.ArrayUtil;
import com.backendsys.modules.common.config.security.annotations.AnonymousProperties;
import com.backendsys.modules.common.config.security.filter.CaptchaVerficationFilter;
import com.backendsys.modules.common.config.security.filter.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
// @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;
//    private final AnonymousFilter anonymousFilter;

    @Bean
    public PasswordEncoder getPw() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CaptchaVerficationFilter CaptchaVerficationFilter() {
        return new CaptchaVerficationFilter();
    }

    @Value("${MAXIMUM_SESSIONS}")
    private Integer MAXIMUM_SESSIONS;

    @Value("#{'${whitelist.static}'.split(',')}")
    private final String[] STATIC_WHITELIST;
    @Value("#{'${whitelist.jwt}'.split(',')}")
    private final String[] JWT_WHITELIST;

    // 获得配置文件中的白名单变量，注意首尾要去空格
    private String[] getWhiteUrls() {
        String [] result = ArrayUtil.addAll(JWT_WHITELIST, STATIC_WHITELIST);
        for (int i = 0; i < result.length; i++) {
            result[i] = result[i].trim();
        }
        return result;
    }

    // Spring-Security 更新日志文档 (升级版本是否对语法有影响)：
    // https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/web/server/ServerHttpSecurity.html

    @Autowired
    private AnonymousProperties anonymousProperties;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        // 在配置文件中的 白名单地址
        String[] whiteUrls = getWhiteUrls();
        // System.out.println(Arrays.toString(whiteUrls));

        // 使用了 @Anonymous 注解的地址
        String[] anonymousUrls = anonymousProperties.getUrls();
        // System.out.println("(SecurityConfig) anonymousUrls:");
        // System.out.println(Arrays.toString(anonymousUrls));

        // 路径授权
        http
            // 禁用csrf(防止跨站请求伪造攻击)
            //.csrf(csrf -> csrf.disable())
            .csrf(AbstractHttpConfigurer::disable)

            // 设置白名单
            .authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
//                    .requestMatchers("/api/**").permitAll()
//                    .requestMatchers(whiteUrls).permitAll()
//                    .requestMatchers(anonymousUrls).permitAll()
//                    .anyRequest().authenticated()
                    .anyRequest().permitAll() // 开放所有mvc页面
            )

            // "/api/auth/login",
            // 对于其他任何请求，都保护起来
            // 禁用缓存
            .sessionManagement((sessionManagement) ->
                sessionManagement
                    .sessionConcurrency((sessionConcurrency) ->
                        sessionConcurrency
                            .maximumSessions(MAXIMUM_SESSIONS)
                            // 限制用户会话并发数量 (防止恶意用户同时使用多个会话进行非法操作)
                            //.expiredUrl("/login?expired")
                    )
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
//            .addFilterBefore(anonymousFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
            ;

        return http.build();
    }

    // 跨域资源配置
    //@Bean
    //public CorsConfigurationSource corsConfigurationSource() {
    //    CorsConfiguration configuration = new CorsConfiguration();
    //    configuration.setAllowedOrigins(Collections.singletonList("*")); // Arrays.asList("*")
    //    configuration.setAllowedMethods(Collections.singletonList("*"));
    //    // "GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH"
    //    configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
    //    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    //    source.registerCorsConfiguration("/**", configuration);
    //    return source;
    //}

}
