package com.arms.api.util.errors;


import com.arms.api.util.response.CommonResponse;
import com.arms.api.util.slack.SlackNotificationService;
import com.arms.api.util.slack.SlackProperty;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * Controller 내에서 발생하는 Exception 대해서 Catch 하여 응답값(Response)을 보내주는 기능을 수행함.
 */
@Slf4j

@RequiredArgsConstructor
@Hidden
@RestControllerAdvice(annotations = RestController.class)
public class ErrorControllerAdvice {

    private final SlackNotificationService slackNotificationService;

    private ResponseEntity<CommonResponse.ApiResult<?>> newResponse(String message, HttpStatus status) {
        HttpHeaders headers = getHttpHeaders();
        return new ResponseEntity<>(CommonResponse.error(message, status), headers, status);
    }

    private HttpHeaders getHttpHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        return headers;
    }

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<?> onException(Exception e) {
        slackNotificationService.sendMessageToChannel(SlackProperty.Channel.engine, e);
        return newResponse(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
    }
    /*
     * connectId 값이 정상적으로 넘어오지 않았을 때 오류 처리
     * */
    @ExceptionHandler(MissingPathVariableException.class)
    public ResponseEntity<?> 커넥트아이디_오류체크(MissingPathVariableException 에러) {

        String variableName = 에러.getVariableName();
        log.error("커넥트 아이디:", 에러);
        if ("connectId".equals(variableName)) {
            return newResponse(ErrorCode.PARAMETER_SERVER_ID_MISSING.getErrorMsg(),HttpStatus.BAD_REQUEST);
        }
        return newResponse(ErrorCode.PARAMETER_SERVER_ID_MISSING.getErrorMsg(),HttpStatus.BAD_REQUEST);
    }

    /**
     * API 호출 시 '객체' 혹은 '파라미터' 데이터 값이 유효하지 않은 경우 @Valid 사용 (추후 필요 가능성)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<?> 전송데이터_유효성체크(MethodArgumentNotValidException 에러) {
        log.error("호출 된 '객체' 혹은 '파라미터' 데이터 값이 유효하지 않습니다 :", 에러);
        return newResponse(ErrorCode.REQUESTED_DATA_INVALID.getErrorMsg(), HttpStatus.BAD_REQUEST);
    }

    /**
     * 잘못된 서버 요청일 경우 발생한 경우(바디에 데이터가 없거나 json 타입이 아닌경우)
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    protected ResponseEntity<?> HttpMessageNotReadableException(HttpMessageNotReadableException 에러) {
        log.error("요청 본문이 없거나 JSON 형식이 아닙니다. ", 에러);
        return newResponse(ErrorCode.REQUEST_BODY_ERROR_CHECK.getErrorMsg(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    protected ResponseEntity<?> handleIllegalArgumentException(IllegalArgumentException 에러) {
        log.error(에러.getMessage());
        return newResponse(에러.getMessage(), HttpStatus.BAD_REQUEST);
    }
}
