package com.infra_automation.config;

import java.util.List;

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.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
@Configuration
public class SecurityConfig {

    private final String authApiBaseURL;
    private final String registrationURL;
    private final String loginURL;
    private final String allowOriginUrl;
    private final List allowMethods;

    @Autowired
    public SecurityConfig(
            @Value("${api.auth.registration.url}") String registrationURL,
            @Value("${api.auth.base.url}") String authApiBaseUrl,
            @Value("${api.auth.login.url}") String loginURL,
            @Value("${auth.allow.origin}") String allowOriginUrl,
            @Value("#{'${auth.allow.method}'.split(',')}") List allowMethods
    ) {
        this.registrationURL = registrationURL;
        this.loginURL = loginURL;
        this.authApiBaseURL = authApiBaseUrl;
        this.allowOriginUrl = allowOriginUrl;
        this.allowMethods = allowMethods;
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("https://ekam.npci.org.in", "http://localhost:3003"));
        configuration.setAllowedMethods(List.of("GET", "POST", "DELETE", "PUT"));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setAllowCredentials(false); // Set to false as requested

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(
            HttpSecurity httpSecurity,
            JwtAuthenticationFilter jwtAuthenticationFilter,
            JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint
    ) throws Exception {

        httpSecurity
                .headers(headers -> headers
                        .addHeaderWriter((request, response) ->
                                response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload"))
                        .addHeaderWriter((request, response) ->
                                response.setHeader("Content-Security-Policy",
                                        "default-src 'self'; " +
                                                "script-src 'self'; " +
                                                "style-src 'self'; " +
                                                "frame-ancestors 'self'; " +
                                                "img-src 'self'; " +
                                                "object-src 'none'; " +
                                                "frame-src 'self'; " +
                                                "form-action 'self'; " +
                                                "media-src 'self';"))
                        .addHeaderWriter((request, response) ->
                                response.setHeader("Expect-CT", "max-age=3600, enforce"))
                        .addHeaderWriter((request, response) ->
                                response.setHeader("X-XSS-Protection", "1; mode=block"))
                        .addHeaderWriter((request, response) ->
                                response.setHeader("X-Content-Type-Options", "nosniff"))
                        .referrerPolicy(referrer ->
                                referrer.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN))
                )
                .cors(Customizer.withDefaults())
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(
                                authApiBaseURL + registrationURL + "/**",
                                authApiBaseURL + loginURL + "/**",
                                "/InfraBk/api/v1/inventory/flushDb",
                                "/InfraBk/api/v1/inventory/upload-inventory"
                        ).permitAll()
                        .anyRequest().authenticated()
                )
                .exceptionHandling(exception ->
                        exception.authenticationEntryPoint(jwtAuthenticationEntryPoint))
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return httpSecurity.build();
    }

    @Bean
    public InMemoryUserDetailsManager userDetailsManager() {
        return new InMemoryUserDetailsManager();
    }

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

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
            throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}