package com.example.dateplanner.configurations;

import com.example.dateplanner.configurations.filters.ErrorHandlingFilter;
import com.example.dateplanner.configurations.handlers.JwtAuthenticationConverter;
import com.example.dateplanner.configurations.handlers.JwtAuthenticationManager;
import com.example.dateplanner.configurations.handlers.JwtAuthenticationSuccessHandler;
import com.example.dateplanner.configurations.handlers.JwtLogoutSuccessHandler;
import com.example.dateplanner.repositories.AppUserRepository;
import com.example.dateplanner.services.JwtService;
import com.example.dateplanner.services.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
import org.springframework.security.web.server.csrf.ServerCsrfTokenRequestAttributeHandler;
import org.springframework.security.web.server.savedrequest.ServerRequestCache;
import org.springframework.security.web.server.savedrequest.WebSessionServerRequestCache;
import java.net.URI;

@Slf4j
@Configuration
@EnableWebFluxSecurity
@RequiredArgsConstructor
@EnableReactiveMethodSecurity
public class SecurityConfig {
    private final AppUserRepository userRepository;
    private final JwtService jwtService;

    @Bean
    public SecurityWebFilterChain filterChain(ServerHttpSecurity http){
        ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
        requestHandler.setTokenFromMultipartDataEnabled(true);

        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(authenticationManager());
        authenticationWebFilter.setServerAuthenticationConverter(authenticationConverter());

        ErrorHandlingFilter errorHandlingFilter = new ErrorHandlingFilter();

        return http
                .csrf(csrf -> csrf.csrfTokenRequestHandler(requestHandler).csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                //.addFilterAfter(errorHandlingFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .authorizeExchange(exchange -> exchange
                        .pathMatchers("/account/login","/error","/error/**", "/account/logout").permitAll()
                        .pathMatchers("/account/**").authenticated()
                        .anyExchange().permitAll()
                )
                .formLogin(loginSpec -> loginSpec.loginPage("/account/login").authenticationSuccessHandler(authenticationSuccessHandler()))
                .logout(logoutSpec -> logoutSpec
                        .logoutUrl("/account/logout")  // ← URL для логаута
                        .logoutSuccessHandler(logoutSuccessHandler()))
                .requestCache(requestCacheSpec -> requestCacheSpec.requestCache(serverRequestCache()))
                .build();
    }

    @Bean
    public ServerRequestCache serverRequestCache() {
        return new WebSessionServerRequestCache();
    }

    @Bean
    public JwtAuthenticationManager authenticationManager() {
        return new JwtAuthenticationManager(jwtService, userService(), passwordEncoder());
    }

    @Bean
    public JwtAuthenticationSuccessHandler authenticationSuccessHandler(){
        return new JwtAuthenticationSuccessHandler(jwtService,serverRequestCache());
    }

    @Bean
    public JwtLogoutSuccessHandler logoutSuccessHandler(){
        JwtLogoutSuccessHandler logoutSuccessHandler = new JwtLogoutSuccessHandler();
        logoutSuccessHandler.setLogoutSuccessUrl(URI.create("/"));
        return logoutSuccessHandler;
    }

    @Bean
    public JwtAuthenticationConverter authenticationConverter(){
        return new JwtAuthenticationConverter();
    }

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

    @Bean
    public UserService userService(){
        return new UserService(userRepository,passwordEncoder());
    }
}
