package com.zioinfo.mall.config;

import com.zioinfo.mall.auth.JwtFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * GUARDiA Mall 보안 — JWT 무상태 + RBAC.
 *
 * <ul>
 *   <li>스토어프론트 조회(상품/카탈로그/리뷰 GET) — 공개</li>
 *   <li>장바구니/주문/결제/배송조회/찜/CS — 인증 고객</li>
 *   <li>상품/카탈로그/프로모션/정산 정의 변경 — MANAGER 이상</li>
 *   <li>관리자 API(/api/admin) — ADMIN (감사/설정 조회는 MANAGER 허용)</li>
 * </ul>
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtFilter jwtFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .cors(cors -> {})
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/mall/auth/**").permitAll()
                .requestMatchers("/actuator/health").permitAll()
                .requestMatchers("/ws/mall/**").permitAll()
                .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/api/mall/docs/**", "/api/mall/swagger/**").permitAll()
                // 스토어프론트 SPA 정적 리소스 + 상품 실이미지 — 공개
                .requestMatchers(HttpMethod.GET,
                        "/", "/index.html", "/favicon.ico", "/favicon.svg", "/robots.txt", "/manifest.json",
                        "/assets/**", "/img/**", "/images/**", "/static/**", "/admin", "/admin/**",
                        "/*.js", "/*.css", "/*.png", "/*.jpg", "/*.jpeg", "/*.gif", "/*.svg", "/*.webp", "/*.ico").permitAll()
                // 스토어프론트 공개 조회 (상품·카탈로그·리뷰·기획전·매장·권역·스케줄 브라우징)
                .requestMatchers(HttpMethod.GET, "/api/mall/product/**", "/api/mall/category/**",
                                                 "/api/mall/review/**", "/api/mall/promotion/**",
                                                 "/api/mall/store/**", "/api/mall/schedule/availability",
                                                 "/api/mall/schedule/holidays").permitAll()
                // ZIP 진입 조회 + 최근접 매장 + 배송지역(공개) — 스토어프론트 진입
                .requestMatchers(HttpMethod.GET, "/api/mall/zone/lookup",
                                                 "/api/mall/zone/nearest",
                                                 "/api/mall/zone/areas").permitAll()
                // 등급 혜택 안내(공개) + 진행중 이벤트/배너(공개 스토어프론트)
                .requestMatchers(HttpMethod.GET, "/api/mall/loyalty/tiers", "/api/mall/loyalty/tiers/**",
                                                 "/api/mall/event/ongoing", "/api/mall/event/banners",
                                                 "/api/mall/event/{id}").permitAll()
                // AI 스토어프론트(추천·리뷰요약·자연어검색·카드메시지) 공개
                .requestMatchers(HttpMethod.GET, "/api/mall/ai/recommend", "/api/mall/ai/review-summary/**").permitAll()
                .requestMatchers(HttpMethod.POST, "/api/mall/ai/nl-search", "/api/mall/ai/card-message").permitAll()
                // 관리자 API
                .requestMatchers("/api/admin/users/**").hasRole("ADMIN")
                .requestMatchers("/api/admin/audit").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers(HttpMethod.GET, "/api/admin/settings").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers("/api/admin/settings/**").hasRole("ADMIN")
                // 운영 분석 — MANAGER 이상
                .requestMatchers("/api/mall/analytics/**").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers("/api/mall/settlement/**").hasAnyRole("ADMIN", "MANAGER")
                // 상품·카탈로그·프로모션·재고 정의 변경 — MANAGER 이상
                .requestMatchers(HttpMethod.POST,   "/api/mall/product/**", "/api/mall/category/**",
                                                    "/api/mall/promotion/**", "/api/mall/inventory/**").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers(HttpMethod.PUT,    "/api/mall/product/**", "/api/mall/category/**",
                                                    "/api/mall/promotion/**", "/api/mall/inventory/**").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers(HttpMethod.DELETE, "/api/mall/product/**", "/api/mall/category/**",
                                                    "/api/mall/promotion/**", "/api/mall/inventory/**").hasAnyRole("ADMIN", "MANAGER")
                // 그 외 mall API (장바구니·주문·결제·배송·찜·CS·회원·AI) — 인증 사용자
                .requestMatchers("/api/mall/**").authenticated()
                // 나머지 모든 API/WS/Actuator는 인증 (아래 SPA permit 보다 먼저 — API 노출 방지)
                .requestMatchers("/api/**", "/ws/**", "/actuator/**").authenticated()
                // 스토어프론트 SPA 딥링크(/app·/cart·/events·/category·/product·/checkout·/mypage·/orders·/search 등)
                // → 정적 index.html 포워드(공개). 실제 인증은 클라이언트 ProtectedRoute + 위 API 규칙에서 강제.
                .requestMatchers(HttpMethod.GET, "/**").permitAll()
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
    @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration cfg) throws Exception { return cfg.getAuthenticationManager(); }
}
