package com.zioinfo.esn.common;

import com.zioinfo.esn.uiws.common.UiwsApiException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 전역 예외 처리(보안 불변규칙: 스택트레이스/SQL/자격증명 미노출).
 *
 * <p>UIWS 이식 모듈 + 2FA 레이어 도입과 함께 추가. 기존 ESN 컨트롤러도 동일 정책으로 보호한다
 * (예외 메시지는 사용자 노출용 요약만 — 내부 원인은 서버 로그에만 남긴다).
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /** UIWS 이식/2FA 도메인 예외 → 400 + 안전한 사용자 메시지. */
    @ExceptionHandler(UiwsApiException.class)
    public ResponseEntity<ApiResponse<Void>> handleUiws(UiwsApiException e) {
        log.debug("[UIWS] {}: {}", e.getErrorCode().getCode(), e.getMessage());
        return ResponseEntity.badRequest().body(ApiResponse.fail(e.getMessage()));
    }

    /** 요청 검증 실패 → 400 + 필드 요약(스택트레이스 없음). */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Void>> handleValidation(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldErrors().stream()
                .findFirst()
                .map(fe -> fe.getDefaultMessage())
                .orElse("요청 값이 올바르지 않습니다.");
        return ResponseEntity.badRequest().body(ApiResponse.fail(msg));
    }

    /** 권한 거부 → 403 (RBAC 가드). */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<ApiResponse<Void>> handleDenied(AccessDeniedException e) {
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ApiResponse.fail("접근 권한이 없습니다."));
    }

    /**
     * 그 외 모든 예외 → 400 + 요약 메시지(기존 ESN 의 RuntimeException("ERR-AUTH-...") 흐름 보존).
     * 스택트레이스/원인은 서버 로그에만 기록하고 응답에는 노출하지 않는다(보안 불변규칙).
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<ApiResponse<Void>> handleRuntime(RuntimeException e, HttpServletRequest req) {
        log.warn("[ERR] {} {} — {}", req.getMethod(), req.getRequestURI(), e.getMessage());
        String msg = e.getMessage() != null ? e.getMessage() : "요청 처리 중 오류가 발생했습니다.";
        return ResponseEntity.badRequest().body(ApiResponse.fail(msg));
    }

    /** 그 외 체크 예외/오류 → 500 + 요약(상세 미노출). */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleOther(Exception e, HttpServletRequest req) {
        log.error("[ERR-500] {} {}", req.getMethod(), req.getRequestURI(), e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(ApiResponse.fail("서버 처리 중 오류가 발생했습니다."));
    }
}
