package incheon.com.cmm.exception;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import incheon.com.cmm.api.DefaultApiResponse;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @Class Name : RestApiExceptionHandler.java
 * @Description : REST API 컨트롤러에서 발생하는 예외를 처리하는 글로벌 예외 핸들러
 * @Modification Information
 *
 *    수정일       수정자         수정내용
 *    -------        -------     -------------------
 *
 */
@Slf4j
@RestControllerAdvice(annotations = RestController.class)
public class RestApiExceptionHandler extends ResponseEntityExceptionHandler {

    @org.springframework.beans.factory.annotation.Value("${spring.profiles.active:local}")
    private String activeProfile;

    private boolean isDevelopmentMode() {
        return "local".equals(activeProfile) || "DEV".equals(activeProfile);
    }
    
    /**
     * 권한 없음 예외 처리 (Spring Security)
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleAccessDeniedException(AccessDeniedException e) {
        log.warn("REST API 접근 권한 없음: {}", e.getMessage());

        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                HttpStatus.FORBIDDEN.value(),
                "접근 권한이 없습니다.",
                "ACCESS_DENIED"
        );

        return new ResponseEntity<>(response, HttpStatus.FORBIDDEN);
    }

    /**
     * 일반적인 예외 처리
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleException(Exception e) {
        log.error("REST API 처리 중 예외 발생: ", e);

        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                HttpStatus.INTERNAL_SERVER_ERROR.value(),
                "서버 내부 오류가 발생했습니다.",
                e.getClass().getSimpleName()
        );

        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    /**
     * 비즈니스 예외 처리
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleBusinessException(BusinessException e) {
        log.error("REST API 처리 중 비즈니스 예외 발생: {}", e.getMessage());
        
        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                e.getStatus().value(),
                e.getMessage(),
                e.getClass().getSimpleName()
        );
        
        return new ResponseEntity<>(response, e.getStatus());
    }
    
    /**
     * 잘못된 요청 예외 처리
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleIllegalArgumentException(IllegalArgumentException e) {
        log.error("REST API 처리 중 잘못된 인자 예외 발생: {}", e.getMessage());

        // 운영 환경에서는 상세 오류 숨김
        String message = isDevelopmentMode() ? e.getMessage() : "잘못된 요청입니다.";

        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                HttpStatus.BAD_REQUEST.value(),
                message,
                "BAD_REQUEST"
        );

        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }
    
    /**
     * 엔티티를 찾을 수 없는 예외 처리
     */
    @ExceptionHandler(EntityNotFoundException.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleEntityNotFoundException(EntityNotFoundException e) {
        log.error("REST API 처리 중 엔티티 찾기 실패: {}", e.getMessage());

        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                HttpStatus.NOT_FOUND.value(),
                e.getMessage(),
                e.getClass().getSimpleName()
        );

        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    /**
     * 데이터 무결성 위반 예외 처리 (중복 키, 외래 키 제약 등)
     */
    @ExceptionHandler(DataIntegrityViolationException.class)
    public ResponseEntity<DefaultApiResponse<Object>> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        log.error("REST API 처리 중 데이터 무결성 위반: {}", e.getMessage());

        String message = "데이터 처리 중 오류가 발생했습니다.";

        // 중복 키 에러 판별
        if (e.getMessage() != null && e.getMessage().contains("duplicate key")) {
            message = "이미 존재하는 코드입니다.";
        }
        // 외래 키 제약 위반
        else if (e.getMessage() != null && e.getMessage().contains("foreign key")) {
            message = "참조 중인 데이터가 있어 삭제할 수 없습니다.";
        }

        DefaultApiResponse<Object> response = DefaultApiResponse.error(
                HttpStatus.CONFLICT.value(),
                message,
                e.getClass().getSimpleName()
        );

        return new ResponseEntity<>(response, HttpStatus.CONFLICT);
    }
    
    /**
     * 유효성 검증 예외 처리 - 부모 클래스의 메서드를 오버라이드
     */
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        
        DefaultApiResponse<Map<String, String>> response = DefaultApiResponse.<Map<String, String>>builder()
                .code(HttpStatus.BAD_REQUEST.value())
                .message("입력값 검증 오류가 발생했습니다.")
                .data(errors)
                .timestamp(java.time.LocalDateTime.now())
                .error("ValidationException")
                .build();
        
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }
} 