package incheon.com.cmm.exception;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import incheon.ags.ias.sys.mapper.SysMapper;
import incheon.ags.ias.sys.vo.SysVO;
import incheon.com.cmm.context.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName : ViewExceptionHandler.java
 * @Description : MVC 컨트롤러의 뷰 템플릿 예외 처리 핸들러
 *
 * @author : 관리자
 * @since  : 2023. 10. 10
 * @version : 1.0
 *
 * <pre>
 * << 개정이력(Modification Information) >>
 *
 *   수정일              수정자               수정내용
 *  -------------  ------------   ---------------------
 *   2023. 10. 10    관리자               최초 생성
 *   2025.10. 2      AI                 환경별 오류 페이지 분기 추가
 * </pre>
 *
 */
@Slf4j
@ControllerAdvice(annotations = Controller.class)
public class ViewExceptionHandler extends ResponseEntityExceptionHandler {

    @Value("${spring.profiles.active:local}")
    private String activeProfile;

    @Resource
    private SysMapper sysMapper;

    /**
     * 권한 없음 예외 처리 (AccessDeniedException 전용)
     * @param e 발생한 권한 예외
     * @param request HTTP 요청 객체
     * @return 오류 페이지 뷰
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ModelAndView handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
        log.error("권한 없음 예외 발생: {}", e.getMessage(), e);

        ModelAndView mav = new ModelAndView();
        mav.addObject("errorMessage", "접근 권한이 없습니다.");
        mav.addObject("errorType", "권한 없음 (403 Forbidden)");
        mav.addObject("requestUri", request.getRequestURI());

        // RequestContext에서 메뉴 정보 가져오기
        String menuNm = RequestContext.getCurrentMenuNm();
        String sysNm = RequestContext.getCurrentSysNm();
        String sysCd = RequestContext.getCurrentSysCd();
        String menuCd = RequestContext.getCurrentMenuCd();

        if (menuNm != null) {
            mav.addObject("menuNm", menuNm);
        }
        if (sysNm != null) {
            mav.addObject("sysNm", sysNm);
        }
        if (sysCd != null) {
            mav.addObject("sysCd", sysCd);

            // 시스템 URL 조회
            try {
                SysVO sysVO = new SysVO();
                sysVO.setSysCd(sysCd);
                SysVO sysInfo = sysMapper.selectSysDetail(sysVO);
                if (sysInfo != null && sysInfo.getSysUrlAddr() != null && !sysInfo.getSysUrlAddr().trim().isEmpty()) {
                    mav.addObject("sysUrl", sysInfo.getSysUrlAddr());
                }
            } catch (Exception ex) {
                log.warn("시스템 URL 조회 실패: sysCd={}, error={}", sysCd, ex.getMessage());
            }
        }
        if (menuCd != null) {
            mav.addObject("menuCd", menuCd);
        }

        mav.setViewName(isDevelopmentMode() ? "error/error-dev" : "error/error");

        return mav;
    }

    /**
     * MVC 컨트롤러에서 발생한 일반 예외 처리
     * @param e 발생한 예외
     * @param request HTTP 요청 객체
     * @return 오류 페이지 뷰
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception e, HttpServletRequest request) {
        log.error("MVC 컨트롤러 처리 중 예외 발생: {}", e.getMessage(), e);

        ModelAndView mav = new ModelAndView();

        // 운영 환경에서는 상세 오류 정보 숨김 (보안)
        if (isDevelopmentMode()) {
            mav.addObject("errorMessage", e.getMessage());
            mav.addObject("errorType", e.getClass().getSimpleName());
        } else {
            mav.addObject("errorMessage", "시스템 처리 중 오류가 발생했습니다. 문제가 지속되면 관리자에게 문의하세요.");
            mav.addObject("errorType", "시스템 오류");
        }
        mav.addObject("requestUri", request.getRequestURI());

        // RequestContext에서 메뉴 정보 가져오기 (있으면 추가)
        String menuNm = RequestContext.getCurrentMenuNm();
        String sysNm = RequestContext.getCurrentSysNm();
        String sysCd = RequestContext.getCurrentSysCd();

        if (menuNm != null) {
            mav.addObject("menuNm", menuNm);
        }
        if (sysNm != null) {
            mav.addObject("sysNm", sysNm);
        }
        if (sysCd != null) {
            mav.addObject("sysCd", sysCd);

            // 시스템 URL 조회
            try {
                SysVO sysVO = new SysVO();
                sysVO.setSysCd(sysCd);
                SysVO sysInfo = sysMapper.selectSysDetail(sysVO);
                if (sysInfo != null && sysInfo.getSysUrlAddr() != null && !sysInfo.getSysUrlAddr().trim().isEmpty()) {
                    mav.addObject("sysUrl", sysInfo.getSysUrlAddr());
                }
            } catch (Exception ex) {
                log.warn("시스템 URL 조회 실패: sysCd={}, error={}", sysCd, ex.getMessage());
            }
        }

        mav.setViewName(isDevelopmentMode() ? "error/error-dev" : "error/error");

        return mav;
    }
    
    /**
     * MVC 컨트롤러에서 발생한 비즈니스 예외 처리
     * @param e 발생한 비즈니스 예외
     * @param request HTTP 요청 객체
     * @return 오류 페이지 뷰
     */
    @ExceptionHandler(BusinessException.class)
    public ModelAndView handleBusinessException(BusinessException e, HttpServletRequest request) {
        log.error("MVC 컨트롤러 처리 중 비즈니스 예외 발생: {}", e.getMessage(), e);
        
        ModelAndView mav = new ModelAndView();
        mav.addObject("errorMessage", e.getMessage());
        mav.addObject("errorType", "비즈니스 규칙 위반");
        mav.addObject("requestUri", request.getRequestURI());
        mav.setViewName(isDevelopmentMode() ? "error/error-dev" : "error/error");
        
        return mav;
    }
    
    /**
     * MVC 컨트롤러에서 발생한 엔티티 찾기 실패 예외 처리
     * @param e 발생한 엔티티 찾기 실패 예외
     * @param request HTTP 요청 객체
     * @return 오류 페이지 뷰
     */
    @ExceptionHandler(EntityNotFoundException.class)
    public ModelAndView handleEntityNotFoundException(EntityNotFoundException e, HttpServletRequest request) {
        log.error("MVC 컨트롤러 처리 중 엔티티 찾기 실패 예외 발생: {}", e.getMessage(), e);
        
        ModelAndView mav = new ModelAndView();
        mav.addObject("errorMessage", e.getMessage());
        mav.addObject("errorType", "데이터 찾기 실패");
        mav.addObject("requestUri", request.getRequestURI());
        mav.setViewName(isDevelopmentMode() ? "error/error-dev" : "error/error");
        
        return mav;
    }
    
    /**
     * 개발 모드 여부 확인
     */
    private boolean isDevelopmentMode() {
        return "local".equals(activeProfile) || "DEV".equals(activeProfile);
    }
} 