package org.lingniu.idp.config;

import org.lingniu.idp.security.filter.login.MobilePasswordAuthenticationFilter;
import org.lingniu.idp.security.handler.AuthenticationEntryPointImpl;
import org.lingniu.idp.security.handler.LoginSuccessHandler;
import org.lingniu.idp.security.handler.LogoutSuccessHandlerImpl;
import org.lingniu.idp.security.provider.MobilePasswordAuthenticationProvider;
import org.lingniu.idp.security.provider.SmsCodeAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.Customizer;
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.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Arrays;
import java.util.List;

@Configuration
//@EnableWebSecurity
public class SecurityConfig {
    



    private final AuthenticationEntryPointImpl unauthorizedHandler;
    private final LogoutSuccessHandlerImpl logoutSuccessHandler;
    private final MobilePasswordAuthenticationProvider mobilePasswordAuthenticationProvider;
    private final SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
    private final LoginSuccessHandler successHandler;

    public SecurityConfig(AuthenticationEntryPointImpl unauthorizedHandler, LogoutSuccessHandlerImpl logoutSuccessHandler, MobilePasswordAuthenticationProvider mobilePasswordAuthenticationProvider, SmsCodeAuthenticationProvider smsCodeAuthenticationProvider, LoginSuccessHandler successHandler) {
        this.unauthorizedHandler = unauthorizedHandler;
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.mobilePasswordAuthenticationProvider = mobilePasswordAuthenticationProvider;
        this.smsCodeAuthenticationProvider = smsCodeAuthenticationProvider;
        this.successHandler = successHandler;
    }

    @Bean
    @Order(2)
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(AbstractHttpConfigurer::disable)
            // 禁用HTTP响应标头
            .headers((headersCustomizer) -> {
                headersCustomizer.cacheControl(HeadersConfigurer.CacheControlConfig::disable).frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin);
            })
            // 认证失败处理类
            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
            // 基于token，所以不需要session
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers(
                    "/api/login/**",
                    "/captcha/image"
                ).permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
            // 添加Logout filter
            .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
            .rememberMe(remember -> remember
                .tokenValiditySeconds(7 * 24 * 60 * 60) // 7天
                .key("remember-me-idp")
            );
        addFilters(http);
        
        return http.build();
    }
    private void addFilters(HttpSecurity http){
        MobilePasswordAuthenticationFilter mobilePasswordAuthenticationFilter = new MobilePasswordAuthenticationFilter(authenticationManager());
        mobilePasswordAuthenticationFilter.setAuthenticationSuccessHandler(successHandler);
        http.addFilterBefore(mobilePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }
    /**
     * 自定义JWT认证转换器
     */
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);

        return jwtAuthenticationConverter;
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> providers = Arrays.asList(
                mobilePasswordAuthenticationProvider,
                smsCodeAuthenticationProvider
        );

        return new ProviderManager(providers);
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String portal = bCryptPasswordEncoder.encode("portal");
        System.out.println(portal);
    }
}