package org.raddatz.familienarchiv.security;

import lombok.RequiredArgsConstructor;

import org.raddatz.familienarchiv.user.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final CustomUserDetailsService userDetailsService;
    private final Environment environment;

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

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // CSRF is intentionally disabled: every request from the SvelteKit frontend
                // carries an explicit Authorization header (Basic Auth token injected by
                // hooks.server.ts). Browsers block cross-origin requests from setting custom
                // headers, so cross-site request forgery via a third-party page is not
                // possible with this auth scheme. If the auth model ever changes to
                // cookie-based sessions, CSRF protection must be re-enabled.
                .csrf(csrf -> csrf.disable())

                .authorizeHttpRequests(auth -> {
                    // Health endpoint must be open so CI/Docker health checks work without credentials
                    auth.requestMatchers("/actuator/health").permitAll();
                    // Password reset endpoints are unauthenticated by nature
                    auth.requestMatchers("/api/auth/forgot-password", "/api/auth/reset-password").permitAll();
                    // Invite-based registration endpoints are public
                    auth.requestMatchers("/api/auth/invite/**", "/api/auth/register").permitAll();
                    // E2E test helper (only active under "e2e" profile)
                    auth.requestMatchers("/api/auth/reset-token-for-test").permitAll();
                    // In dev, allow unauthenticated access to the OpenAPI spec and Swagger UI
                    if (environment.matchesProfiles("dev")) {
                        auth.requestMatchers(
                            "/v3/api-docs/**",
                            "/swagger-ui/**",
                            "/swagger-ui.html"
                        ).permitAll();
                    }
                    auth.anyRequest().authenticated();
                })
                // erlaubt pdf im Iframe
                .headers(headers -> headers
                        .frameOptions(frameOptions -> frameOptions.sameOrigin()))
                // Erlaubt Login via Browser-Popup oder REST-Header (Authorization: Basic ...)
                .httpBasic(Customizer.withDefaults())
                .formLogin(form -> form.usernameParameter("email"));

        return http.build();
    }
}
