package com.social.media.infrastructure.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.web.cors.CorsConfigurationSource;

/**
 * Security Configuration
 * Configures Spring Security for the application
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CorsConfigurationSource corsConfigurationSource;

    public SecurityConfig(CorsConfigurationSource corsConfigurationSource) {
        this.corsConfigurationSource = corsConfigurationSource;
    }

    /**
     * Main security filter chain configuration
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            // Disable CSRF for REST APIs
            .csrf(AbstractHttpConfigurer::disable)
            
            // Enable CORS with our configuration
            .cors(cors -> cors.configurationSource(corsConfigurationSource))
            
            // Configure session management
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            
            // Configure authorization
            .authorizeHttpRequests(auth -> auth
                // Allow all requests to auth endpoints
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/v1/auth/**").permitAll()
                
                // Allow company registration
                .requestMatchers("/api/v1/companies").permitAll()
                
                // Allow actuator endpoints
                .requestMatchers("/actuator/**").permitAll()
                
                // Allow Swagger/OpenAPI endpoints
                .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
                
                // Allow error endpoint
                .requestMatchers("/error").permitAll()
                
                // For development, allow all requests (you can restrict this later)
                .anyRequest().permitAll()
            )
            
            // Disable form login
            .formLogin(AbstractHttpConfigurer::disable)
            
            // Disable HTTP Basic authentication
            .httpBasic(AbstractHttpConfigurer::disable)
            
            // Disable logout (we'll handle it manually)
            .logout(AbstractHttpConfigurer::disable);

        return http.build();
    }

    /**
     * Password encoder bean for password hashing
     * Custom implementation to support both $2a$ and $2b$ BCrypt versions
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            private final BCryptPasswordEncoder bCryptEncoder = new BCryptPasswordEncoder();

            @Override
            public String encode(CharSequence rawPassword) {
                return bCryptEncoder.encode(rawPassword);
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                // Handle both $2a$ and $2b$ BCrypt versions
                if (encodedPassword.startsWith("$2b$")) {
                    // Convert $2b$ to $2a$ for compatibility with Spring Security
                    String convertedHash = encodedPassword.replace("$2b$", "$2a$");
                    return bCryptEncoder.matches(rawPassword, convertedHash);
                }
                return bCryptEncoder.matches(rawPassword, encodedPassword);
            }
        };
    }
}
