package incheon.com.config;

import incheon.com.cmm.api.DefaultApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.AccessDeniedException;
import java.sql.SQLException;

/**
 * 전역 예외 처리기
 * REST API와 MVC 예외 처리를 통합하여 표준화된 응답 형식을 제공
 *
 * @author 이재룡
 * @since 2025.09.02
 * @version 2.0.0
 */
@Slf4j
@RestControllerAdvice(basePackages = "incheon.uis.ums")
public class UisGlobalExceptionHandler {

    /**
     * IllegalArgumentException 처리
     * 잘못된 파라미터 값이 전달되었을 때 발생
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleIllegalArgumentException(
            IllegalArgumentException ex, WebRequest request) {

        log.warn("잘못된 파라미터: {}", ex.getMessage());

        return ResponseEntity.badRequest()
                .body(DefaultApiResponse.error(400, "잘못된 요청 파라미터입니다.", ex.getMessage()));
    }

    /**
     * NullPointerException 처리
     * null 값 참조 시 발생
     */
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleNullPointerException(
            NullPointerException ex, WebRequest request) {

        log.error("NullPointerException 발생: ", ex);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(DefaultApiResponse.error(500, "서버 내부 오류가 발생했습니다.", "NULL_POINTER"));
    }

    /**
     * SQLException 처리
     * 데이터베이스 관련 예외
     */
    @ExceptionHandler(SQLException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleSQLException(
            SQLException ex, WebRequest request) {

        log.error("데이터베이스 오류 발생: ", ex);

        String errorMessage = "데이터베이스 처리 중 오류가 발생했습니다.";
        if (ex.getMessage() != null && ex.getMessage().contains("duplicate")) {
            errorMessage = "중복된 데이터가 존재합니다.";
        } else if (ex.getMessage() != null && ex.getMessage().contains("foreign key")) {
            errorMessage = "참조 무결성 제약 조건 위반입니다.";
        }

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(DefaultApiResponse.error(500, errorMessage, "DATABASE_ERROR"));
    }

    /**
     * AccessDeniedException 처리
     * 접근 권한이 없는 경우
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleAccessDeniedException(
            AccessDeniedException ex, WebRequest request) {

        log.warn("접근 권한 없음: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.FORBIDDEN)
                .body(DefaultApiResponse.error(403, "접근 권한이 없습니다.", "ACCESS_DENIED"));
    }

    /**
     * NumberFormatException 처리
     * 숫자 형식 변환 실패
     */
    @ExceptionHandler(NumberFormatException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleNumberFormatException(
            NumberFormatException ex, WebRequest request) {

        log.warn("숫자 형식 변환 실패: {}", ex.getMessage());

        return ResponseEntity.badRequest()
                .body(DefaultApiResponse.error(400, "올바른 숫자 형식을 입력해주세요.", "INVALID_NUMBER_FORMAT"));
    }

    /**
     * IllegalStateException 처리
     * 객체 상태가 잘못된 경우
     */
    @ExceptionHandler(IllegalStateException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleIllegalStateException(
            IllegalStateException ex, WebRequest request) {

        log.error("잘못된 객체 상태: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(DefaultApiResponse.error(500, "서버 상태가 올바르지 않습니다.", "ILLEGAL_STATE"));
    }

    /**
     * UnsupportedOperationException 처리
     * 지원하지 않는 작업을 시도한 경우
     */
    @ExceptionHandler(UnsupportedOperationException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleUnsupportedOperationException(
            UnsupportedOperationException ex, WebRequest request) {

        log.warn("지원하지 않는 작업: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED)
                .body(DefaultApiResponse.error(501, "지원하지 않는 기능입니다.", "NOT_IMPLEMENTED"));
    }

    /**
     * 그 외 모든 예외 처리
     * 예상하지 못한 예외들을 처리
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleGlobalException(
            Exception ex, WebRequest request) {

        log.error("예상하지 못한 예외 발생: ", ex);

        // HttpServletRequest에서 추가 정보 추출
        String requestUri = "";
        if (request instanceof org.springframework.web.context.request.ServletWebRequest) {
            HttpServletRequest servletRequest = ((org.springframework.web.context.request.ServletWebRequest) request).getRequest();
            requestUri = servletRequest.getRequestURI();
        }

        String errorMessage = String.format("요청 처리 중 오류가 발생했습니다. (URI: %s)", requestUri);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(DefaultApiResponse.error(500, errorMessage, "INTERNAL_SERVER_ERROR"));
    }

    /**
     * RuntimeException 처리
     * 런타임 예외들을 별도로 처리
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<DefaultApiResponse<Void>> handleRuntimeException(
            RuntimeException ex, WebRequest request) {

        log.error("런타임 예외 발생: ", ex);

        String errorType = ex.getClass().getSimpleName();
        String errorMessage = "런타임 오류가 발생했습니다.";

        if (ex instanceof IllegalStateException) {
            errorMessage = "서버 상태가 올바르지 않습니다.";
        } else if (ex instanceof UnsupportedOperationException) {
            errorMessage = "지원하지 않는 기능입니다.";
        }

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(DefaultApiResponse.error(500, errorMessage, errorType));
    }
}
