package com.flightticket.config;

import com.flightticket.security.JwtAuthenticationFilter;
import com.flightticket.security.RateLimitingFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
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.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    
    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final RateLimitingFilter rateLimitingFilter;
    
    public SecurityConfig(@Lazy JwtAuthenticationFilter jwtAuthenticationFilter, 
                         RateLimitingFilter rateLimitingFilter) {
        this.jwtAuthenticationFilter = jwtAuthenticationFilter;
        this.rateLimitingFilter = rateLimitingFilter;
    }
    
    /**
     * Configure security filter chain with JWT authentication and role-based access control
     * Requirements: 1.4, 1.6, 2.1
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configure(http))
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> 
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                // Public endpoints
                .requestMatchers("/api/v1/auth/**").permitAll()
                .requestMatchers("/actuator/health", "/actuator/info").permitAll()
                
                // Swagger UI and API documentation
                .requestMatchers("/swagger-ui/**", "/swagger-ui.html").permitAll()
                .requestMatchers("/v3/api-docs/**", "/api-docs/**").permitAll()
                .requestMatchers("/swagger-resources/**", "/webjars/**").permitAll()
                
                // Super Admin only endpoints
                .requestMatchers("/api/v1/admin/**").hasRole("SUPER_ADMIN")
                .requestMatchers("/api/v1/agencies/*/verify").hasRole("SUPER_ADMIN")
                .requestMatchers("/api/v1/agencies/pending-verification").hasRole("SUPER_ADMIN")
                .requestMatchers("/api/v1/wallet/recharge/*/approve").hasRole("SUPER_ADMIN")
                .requestMatchers("/api/v1/wallet/recharge/*/reject").hasRole("SUPER_ADMIN")
                .requestMatchers("/api/v1/back-office/**").hasRole("SUPER_ADMIN")
                
                // Agency Admin endpoints
                .requestMatchers("/api/v1/users/**").hasAnyRole("SUPER_ADMIN", "AGENCY_ADMIN", "HR_USER")
                
                // Finance User endpoints
                .requestMatchers("/api/v1/wallet/**").hasAnyRole("SUPER_ADMIN", "FINANCE_USER")
                .requestMatchers("/api/v1/reports/admin/**").hasAnyRole("SUPER_ADMIN", "ADMIN")
                .requestMatchers("/api/v1/reports/**").hasAnyRole("SUPER_ADMIN", "FINANCE_USER")
                
                // Agent endpoints
                .requestMatchers("/api/v1/flights/**").hasAnyRole("SUPER_ADMIN", "AGENT")
                .requestMatchers("/api/v1/bookings/**").hasAnyRole("SUPER_ADMIN", "AGENT")
                .requestMatchers("/api/v1/tickets/**").hasAnyRole("SUPER_ADMIN", "AGENT")
                
                // All authenticated users
                .requestMatchers("/api/v1/**").authenticated()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
            )
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(rateLimitingFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
    
    /**
     * Configure JWT authentication converter to extract roles from Keycloak token
     * Requirements: 1.3, 1.4
     */
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
            System.out.println("=== JWT CONVERTER DEBUG ===");
            System.out.println("All claims: " + jwt.getClaims());
            
            // Extract roles from realm_access.roles claim
            Map<String, Object> realmAccess = jwt.getClaimAsMap("realm_access");
            System.out.println("realm_access: " + realmAccess);
            
            if (realmAccess == null || !realmAccess.containsKey("roles")) {
                System.out.println("No realm_access or roles found!");
                return Collections.emptyList();
            }
            
            @SuppressWarnings("unchecked")
            List<String> roles = (List<String>) realmAccess.get("roles");
            System.out.println("Extracted roles: " + roles);
            
            Collection<GrantedAuthority> authorities = roles.stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.<GrantedAuthority>toList());
            
            System.out.println("Granted authorities: " + authorities);
            System.out.println("=== END JWT CONVERTER DEBUG ===");
            
            return authorities;
        });
        
        return jwtAuthenticationConverter;
    }
    
    /**
     * Configure role hierarchy where higher roles inherit permissions from lower roles
     * SUPER_ADMIN > AGENCY_ADMIN > HR_USER, FINANCE_USER, AGENT
     * Requirements: 2.1
     */
    @Bean
    public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        String hierarchy = """
            ROLE_SUPER_ADMIN > ROLE_AGENCY_ADMIN
            ROLE_AGENCY_ADMIN > ROLE_HR_USER
            ROLE_AGENCY_ADMIN > ROLE_FINANCE_USER
            ROLE_AGENCY_ADMIN > ROLE_AGENT
            """;
        roleHierarchy.setHierarchy(hierarchy);
        return roleHierarchy;
    }
    
    /**
     * Configure CORS to allow frontend access
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200", "http://localhost:3000"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setExposedHeaders(Arrays.asList("Authorization", "Content-Type"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
