package com.bio.bio_backend.global.security;

import com.bio.bio_backend.global.filter.JwtTokenIssuanceFilter;
import com.bio.bio_backend.global.filter.JwtTokenValidationFilter;
import com.bio.bio_backend.global.config.CorsConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

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 org.springframework.web.filter.CorsFilter;

import com.fasterxml.jackson.databind.ObjectMapper;


import com.bio.bio_backend.domain.base.member.service.MemberService;
import com.bio.bio_backend.domain.base.member.mapper.MemberMapper;
import com.bio.bio_backend.global.exception.CustomAuthenticationFailureHandler;
import com.bio.bio_backend.global.utils.JwtUtils;
import com.bio.bio_backend.global.utils.HttpUtils;
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 HttpUtils httpUtils;
    private final MemberMapper memberMapper;
    private final CorsConfig corsConfig; // CorsConfig 주입

    // CORS 필터 빈 가져오기
    private CorsFilter getCorsFilter() {
        return corsConfig.corsFilter();
    }

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

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


    /**
     * 공개 경로용 SecurityFilterChain (우선순위 1)
     * 
     * 처리 경로:
     * - 인증 관련: /login, /logout, /members/register
     * - API 문서: /swagger-ui/**, /api-docs/**
     * - WebSocket: /ws/**
     * - 모니터링: /actuator/**
     * 
     * 모든 경로는 인증 없이 접근 가능
     */
    @Bean
    @Order(1)
    SecurityFilterChain publicChain(HttpSecurity http) throws Exception {
        http
            .securityMatcher(
                // 인증 관련 공개 경로
                "/logout", "/members/register",
                
                // Swagger UI 관련 경로
                "/swagger-ui/**", "/swagger-ui.html", "/swagger-ui/index.html",
                
                // API 문서 관련 경로
                "/api-docs", "/api-docs/**", "/v3/api-docs", "/v3/api-docs/**",
                
                // WebSocket 관련 경로
                "/ws/**",
                
                // Actuator 모니터링 경로
                "/actuator/**", "/actuator/health/**", "/actuator/info"
            )
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
            .sessionManagement(session -> 
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
            //.addFilterBefore(getCorsFilter(), UsernamePasswordAuthenticationFilter.class);    // cors를 nginx 통해 처리 중
        return http.build();
    }

    /**
     * API 경로용 SecurityFilterChain (우선순위 2)
     * 
     * 처리 경로: publicChain에서 처리되지 않는 모든 경로
     * - 비즈니스 API 엔드포인트
     * - 사용자 데이터 관련 API
     * - 관리자 기능 API
     * 
     * 모든 요청에 대해 JWT 토큰 인증 필수
     */
    @Bean
    @Order(2)
    SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
        // AuthenticationManager 설정
        AuthenticationManagerBuilder authenticationManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(memberService).passwordEncoder(bCryptPasswordEncoder);

        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();

        http
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .authenticationManager(authenticationManager)
            .sessionManagement(session -> 
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .logout(AbstractHttpConfigurer::disable)
            //.addFilterBefore(getCorsFilter(), UsernamePasswordAuthenticationFilter.class)     // cors를 nginx 통해 처리 중
            .addFilterBefore(getJwtTokenIssuanceFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)  // 토큰 발급
            .addFilterBefore(getJwtTokenValidationFilter(), UsernamePasswordAuthenticationFilter.class);  // 토큰 검증

        return http.build();
    }
}
