package com.samsung.common.handler;

import com.samsung.core.exception.AuthenticationException;
import com.samsung.core.exception.AuthorizationException;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

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

@ControllerAdvice
@Log4j2
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> springHandleNotFound(Exception ex) {
        RestErrorResponse restErrorResponse = new RestErrorResponse();

        ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
        if (status != null) {
            //인증 오류 처리
            if (ex instanceof AuthenticationException) {
                setRestErrorResponse(ex, restErrorResponse, status);
                restErrorResponse.setCode(((AuthenticationException) ex).getCode());
            } else if (ex instanceof AuthorizationException) {
                setRestErrorResponse(ex, restErrorResponse, status);
                restErrorResponse.setCode(403);
            }
        } else {
            restErrorResponse.setStatus(HttpStatus.OK);
            restErrorResponse.setCode(500);
            restErrorResponse.setReason("sdl.commonError");
            restErrorResponse.setTimestamp(new Date());
        }
        Map<String, RestErrorResponse> error = new HashMap<>();
        error.put("error", restErrorResponse);
        if (ex instanceof AuthenticationException || ex instanceof AuthorizationException) {
            log.error(ex.getMessage());
        } else {
            log.error(ex.getMessage(), ex);
        }
        return new ResponseEntity<>(error, restErrorResponse.getStatus());
    }

    private void setRestErrorResponse(Exception ex, RestErrorResponse restErrorResponse, ResponseStatus status) {
        restErrorResponse.setStatus(status.code());
        restErrorResponse.setReason(status.reason());
        restErrorResponse.setTimestamp(new Date());
        restErrorResponse.setMessage(ex.getMessage());
        restErrorResponse.setException(ex.getClass().getSimpleName());
    }
}
