package com.devjob.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * EP12: 예외를 한 곳에서 일관된 형식의 에러 응답으로 변환한다.
 * 1) ErrorCode(Enum) 2) BusinessException 3) GlobalExceptionHandler 의 3단 구조.
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 우리가 의도적으로 던진 비즈니스 예외 → ErrorCode에 정의된 상태/메시지로 응답.
     * 예: throw new BusinessException(ErrorCode.MEMBER_NOT_FOUND) → 404
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusiness(BusinessException ex) {
        log.warn("Business exception: {}", ex.getErrorCode());
        return ResponseEntity
                .status(ex.getErrorCode().getStatus())
                .body(ErrorResponse.of(ex.getErrorCode()));
    }

    /**
     * @Valid 검증 실패 → 400 Bad Request, 어떤 필드가 왜 실패했는지 포함.
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
        return ResponseEntity.badRequest()
                .body(ErrorResponse.validationError(ex));
    }

    /**
     * 존재하지 않는 경로/리소스 요청 → 404. (전용 매핑이 없으면 아래 캐치올이 500으로 처리한다)
     */
    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(NoResourceFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(ErrorResponse.of(ErrorCode.RESOURCE_NOT_FOUND));
    }

    /**
     * 그 외 예상하지 못한 예외 → 500 Internal Server Error.
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex) {
        log.error("Unexpected exception", ex);
        return ResponseEntity.internalServerError()
                .body(ErrorResponse.of(ErrorCode.INTERNAL_ERROR));
    }
}
