package com.kospo.talk.config.security;

import com.kospo.talk.config.filter.AuthenticationFilter;
import com.kospo.talk.config.filter.CustomBasicAuthenticationFilter;
import com.kospo.talk.config.filter.SecurityExceptionFilter;
import com.kospo.talk.repository.UserRepository;
import com.kospo.talk.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;

import java.util.Arrays;

@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
    private final UserService userService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http,
                                                   UserRepository userRepository) throws Exception {
        http
        .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
            .requestMatchers("/admin*").hasRole("ADMIN")
            .anyRequest().authenticated()
        )
        .csrf(AbstractHttpConfigurer::disable)
        .formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer.disable())
        .addFilterBefore(new CustomBasicAuthenticationFilter(authenticationManager(), userRepository), UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new SecurityExceptionFilter(), CustomBasicAuthenticationFilter.class)
        .sessionManagement(httpSecuritySessionManagementConfigurer ->
                httpSecuritySessionManagementConfigurer
                        .maximumSessions(1)
                        .sessionRegistry(sessionRegistry())
        )
        .cors(httpSecurityCorsConfigurer -> httpSecurityCorsConfigurer.configurationSource(new CorsConfigurationSource() {
            @Override
            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                CorsConfiguration config = new CorsConfiguration();
                String origin = request.getHeader("Origin");
                config.setAllowCredentials(true);
                config.setAllowedOrigins(Arrays.asList("http://kisp.kospo.co.kr:8010", "http://localhost:8010", "http://talk.kospo.co.kr:3000"));
                config.setAllowedMethods(Arrays.asList("POST","GET","DELETE","PUT","OPTIONS"));
                config.setAllowedHeaders(Arrays.asList("*"));
                return config;
            }
        }));
        return http.build();
    }

    private String getEncoding (String str) {
        BCryptPasswordEncoder b = new BCryptPasswordEncoder();
        return b.encode(str);
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }


    @Bean
    public AuthenticationManager authenticationManager() {
        AuthenticationManager manager = new AuthenticationManager() {
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                return authentication;
            }
        };
        return manager;
    }


    /*특정 url 필터 제외 처리*/
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(
            "/manifest.json", "/css/**", "/images/**", "/js/**", "/pages/**"
            // -- Swagger UI v2
            , "/v2/api-docs/**", "/swagger-resources/**", "/v3/api-docs/**"
            , "/swagger-ui/**", "/webjars/**", "/swagger/**", "/api-docs/**"
        );
    }


    @Bean
    public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(sessionRegistry());
    }
}

