package com.zioinfo.kintex.common.error;

import com.zioinfo.kintex.common.ApiResponse;
import com.zioinfo.kintex.common.ApiResponse.ApiError;
import com.zioinfo.kintex.system.errorlog.ErrorLogService;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 전역 예외 처리 — 응답에는 코드+요약 메시지만 노출한다.
 * 스택트레이스·내부 세부는 서버 로그에만 남기고 클라이언트에는 절대 반환하지 않는다(보안 불변).
 * 예상치 못한 500 은 관리 조회용으로 요약 1줄만 error_log 에 best-effort 적재한다(스택 미저장).
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    private final ErrorLogService errorLog;

    public GlobalExceptionHandler(ErrorLogService errorLog) {
        this.errorLog = errorLog;
    }

    @ExceptionHandler(ApiException.class)
    public ResponseEntity<ApiResponse<Void>> handleApi(ApiException ex) {
        ErrorCode code = ex.getCode();
        // 로그에만 상세, 응답에는 요약만.
        log.warn("ApiException [{}]: {}", code, ex.getMessage());
        return ResponseEntity.status(code.status())
                .body(ApiResponse.fail(new ApiError(code.name(), ex.getMessage())));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Void>> handleValidation(MethodArgumentNotValidException ex) {
        String msg = ex.getBindingResult().getFieldErrors().stream()
                .findFirst()
                .map(f -> f.getField() + ": " + f.getDefaultMessage())
                .orElse(ErrorCode.VALIDATION.defaultMessage());
        return ResponseEntity.status(ErrorCode.VALIDATION.status())
                .body(ApiResponse.fail(new ApiError(ErrorCode.VALIDATION.name(), msg)));
    }

    /** 최종 방어선 — 예상치 못한 예외는 요약 메시지만, 상세는 로그로. */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleUnexpected(Exception ex, HttpServletRequest req) {
        log.error("Unhandled exception", ex);
        ErrorCode code = ErrorCode.INTERNAL;
        // 요약 1줄만(예외 클래스 + 메시지 절단). 스택트레이스·민감정보는 저장하지 않는다.
        String summary = ex.getClass().getSimpleName()
                + (ex.getMessage() == null ? "" : ": " + ex.getMessage());
        errorLog.record(code.name(), summary,
                req == null ? null : req.getRequestURI(),
                req == null ? null : req.getMethod(), null);
        return ResponseEntity.status(code.status())
                .body(ApiResponse.fail(new ApiError(code.name(), code.defaultMessage())));
    }
}
