package com.bio.bio_backend.global.security;

import com.bio.bio_backend.global.filter.JwtTokenIssuanceFilter;
import com.bio.bio_backend.global.filter.JwtTokenValidationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.fasterxml.jackson.databind.ObjectMapper;


import com.bio.bio_backend.domain.base.member.service.MemberService;
import com.bio.bio_backend.global.exception.CustomAuthenticationFailureHandler;
import com.bio.bio_backend.global.utils.JwtUtils;
import com.bio.bio_backend.global.config.SecurityPathConfig;
import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurity {

    private final MemberService memberService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final JwtUtils jwtUtils;
    private final ObjectMapper objectMapper;
    private final Environment env;
    private final SecurityPathConfig securityPathConfig;

    private JwtTokenIssuanceFilter getJwtTokenIssuanceFilter(AuthenticationManager authenticationManager) throws Exception {
        JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper);
        filter.setFilterProcessesUrl("/login");
        filter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler(objectMapper));
        return filter;
    }

    private JwtTokenValidationFilter getJwtTokenValidationFilter() {
        return new JwtTokenValidationFilter(jwtUtils, memberService, env, securityPathConfig);
    }


    
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        // AuthenticationManager 설정
        AuthenticationManagerBuilder authenticationManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(memberService).passwordEncoder(bCryptPasswordEncoder);

        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();

        // 설정 파일에서 허용할 경로 가져오기
        String[] permitAllPaths = securityPathConfig.getPermitAllPaths().toArray(new String[0]);

        http.csrf(AbstractHttpConfigurer::disable)          //csrf 비활성화
                .authorizeHttpRequests(request ->               //request 허용 설정
                        request
                            .requestMatchers(permitAllPaths).permitAll()  // 설정 파일에서 허용할 경로
                            .anyRequest().authenticated()  // 나머지 요청은 인증 필요
                )
                .authenticationManager(authenticationManager)
                .sessionManagement(session -> 
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // 세션 사용 안함
                )
                .logout(AbstractHttpConfigurer::disable);
        http
            // 1단계: JWT 토큰 발급 필터 (로그인 요청 처리 및 토큰 발급)
            .addFilterBefore(getJwtTokenIssuanceFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)
            // 2단계: JWT 토큰 검증 필터 (자동 토큰 갱신 포함)
            .addFilterBefore(getJwtTokenValidationFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}
