package com.spring.common.error;

import java.util.Objects;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 전역 오류 처리를 위한 컨트롤러 클래스입니다.
 * 
 * <p>이 클래스는 Spring MVC의 ErrorController 인터페이스를 구현하여
 * 애플리케이션에서 발생하는 오류를 처리합니다.</p>
 * 
 * <p>HTTP 오류가 발생했을 때 사용자에게 오류 페이지를 표시하는 기능을 제공합니다.</p>
 * 
 * <p>이 컨트롤러는 JSON 요청과 HTML 요청을 구분하여 각각에 맞는 오류 처리를 수행합니다.</p>
 * 
 * @author mindol
 * @version 1.0
 */
@Controller
public class GlobalErrorController implements ErrorController {

    /**
     * 오류를 처리하는 메서드입니다.
     * 
     * @param request HTTP 요청 객체
     * @param model 모델 객체
     * @return JSON 요청일 경우 JSON 오류 응답, HTML 요청일 경우 HTML 오류 페이지
     */
    @GetMapping("/error")
    public Object handleError(HttpServletRequest request, Model model) {
        if (isJsonRequest(request)) {
            return handleJsonError(request);
        } else {
            return handleHtmlError(request, model);
        }
    }

    /**
     * 요청이 JSON 형식인지 확인하는 메서드입니다.
     * 
     * @param request HTTP 요청 객체
     * @return JSON 요청이면 true, 그렇지 않으면 false
     */
    private boolean isJsonRequest(HttpServletRequest request) {
        return Objects.equals(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
    }

    /**
     * JSON 요청에 대한 오류를 처리하는 메서드입니다.
     * 
     * @param request HTTP 요청 객체
     * @return BizErrorResponse 객체와 HTTP 상태 코드를 포함한 ResponseEntity
     */
    private ResponseEntity<BizErrorResponse> handleJsonError(HttpServletRequest request) {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        int statusCode = status != null ? Integer.parseInt(status.toString()) : HttpStatus.INTERNAL_SERVER_ERROR.value();
        HttpStatus httpStatus = HttpStatus.valueOf(statusCode);
        return new ResponseEntity<>(BizErrorResponse.fromErrorRule(ExceptionRule.NOT_FOUND), httpStatus);
    }

    /**
     * HTML 요청에 대한 오류를 처리하는 메서드입니다.
     * 
     * @param request HTTP 요청 객체
     * @param model 모델 객체
     * @return 오류 페이지의 경로
     */
    private String handleHtmlError(HttpServletRequest request, Model model) {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        String errorMessage = String.valueOf(request.getAttribute(RequestDispatcher.ERROR_MESSAGE));
        String statusMsg = status.toString();
        HttpStatus httpStatus = HttpStatus.valueOf(Integer.valueOf(statusMsg));
        model.addAttribute("message", statusMsg + " " + httpStatus.getReasonPhrase());
        if (StringUtils.hasText(errorMessage)) {
            model.addAttribute("errorMessage", errorMessage);
        }
        return "pages/error/error";
    }

}
