package pl.dmcs.userservice.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod;
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.annotation.web.configurers.AbstractHttpConfigurer;
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.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;

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

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    @Bean
    @ConditionalOnProperty(name = "app.security.enabled", havingValue = "true", matchIfMissing = true)
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/api/internal/user/webhook/**").permitAll()
                        .requestMatchers(HttpMethod.GET, "/api/user/internal/couriers").permitAll()
                        .requestMatchers("/api/user/public/**").permitAll()
                        .requestMatchers("/api/transport/courier/**").permitAll()
                        .requestMatchers(HttpMethod.GET, "/api/transport/{id}").permitAll()
                        .requestMatchers(HttpMethod.GET, "/api/transport").permitAll()
                        .requestMatchers("/api/user/internal/**").permitAll()
                        .anyRequest().authenticated())
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt ->
                        jwt.jwtAuthenticationConverter(jwtAuthConverter())
                ));
        return http.build();
    }

    @Bean
    @ConditionalOnProperty(name = "app.security.enabled", havingValue = "false")
    public SecurityFilterChain securityDisabled(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
                .csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }

    @Bean
    public JwtAuthenticationConverter jwtAuthConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(new Converter<Jwt, Collection<GrantedAuthority>>() {
            @Override
            public Collection<GrantedAuthority> convert(Jwt jwt) {
                Map<String, Object> realmAccess = jwt.getClaim("realm_access");
                if (realmAccess == null || realmAccess.isEmpty()) {
                    System.out.println("[JwtAuthConverter] realmAccess is null or empty");
                    return Collections.emptyList();
                }

                Collection<String> roles = (Collection<String>) realmAccess.get("roles");
                if (roles == null) {
                    return Collections.emptyList();
                }

                Collection<GrantedAuthority> authorities = roles.stream()
                        .map(role -> {
                            String upperRole = role.toUpperCase();
                            System.out.println("[JwtAuthConverter] Converting role: " + role + " -> " + upperRole);
                            return new SimpleGrantedAuthority(upperRole);
                        })
                        .collect(Collectors.toList());

                return authorities;
            }
        });
        return converter;
    }
}
