package com.app.framework.core.exception.global.controller;

import cn.hutool.extra.spring.SpringUtil;
import com.app.framework.core.exception.ValidException;
import com.app.framework.core.exception.global.appender.ExceptionAppenderBase;
import com.app.framework.core.support.view.form.AjaxResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;

/**
 * 异常中心控制器
 * 	此处可将异常入库备查
 */
@ControllerAdvice
public class ExceptionCenterController {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionCenterController.class.getName());

    private static String argEx[] = {"ClientAbortException"};

	@ExceptionHandler(value = ValidException.class)
	@ResponseBody
	public AjaxResult exceptionHandler(HttpServletRequest request, ValidException ex){
		return AjaxResult.wrapError(ex.getMessage());
	}

	@ExceptionHandler(value = Exception.class)
	@ResponseBody
	public AjaxResult exceptionHandler(HttpServletRequest request, HandlerMethod handlerMethod, Exception ex){
		/*
		 * 处理忽略异常
		 */
		if (isIgnoreException(ex)) {
			return null;
		}

		//异常记录
		ExceptionAppenderBase appender = SpringUtil.getBean(ExceptionAppenderBase.class);
		if(appender != null){
			appender.append(request, handlerMethod, ex, System.currentTimeMillis());
		}

		//异常输出至控制台
		ex.printStackTrace();

		String error = this.processException(ex);
		return AjaxResult.wrapError(error);
	}

    private boolean isIgnoreException(Exception e) {
       for (String name : argEx) {
           if (name.equals(e.getClass().getSimpleName())) {
               return true;
           }
       }
      return false;
    }
    
    private String processException(Throwable exception) {
    	String resultError = "";
		if (exception instanceof DataIntegrityViolationException) {
			String errorMsg = exception.getMessage();
			if (errorMsg.indexOf("ORA-02291") >= 0) {
				errorMsg = ExceptionMsgConst.MSG_INSERT_FAILED_NOPARENT; // 外键引用的表中无此记录（通常情况下可能不会出现此异常，因为前台页面上应该是从下拉列表框中选择而非手工输入数据）
			} else if (errorMsg.indexOf("ORA-02292") >= 0) {
				errorMsg = ExceptionMsgConst.MSG_DELETE_FAILED_REFERENCED;// 作为别的表中的外键且数据被引用
			} else if (errorMsg.indexOf("ORA-00001") >= 0) {
				errorMsg = ExceptionMsgConst.MSG_INSERT_FAILED_NOTUNIQUE; // 数据不唯一
			} else {
				errorMsg = ExceptionMsgConst.MSG_FAILED_OTHER;
			}
//			log.error("数据违反唯一约束条件", exception);
			resultError = errorMsg;
		} else if (exception instanceof DataAccessException) {
//			log.error("数据访问异常", exception);
			resultError = ExceptionMsgConst.MSG_FAILED_OTHER;
		} else if (exception instanceof ConstraintViolationException) {
//			log.error("业务方法执行异常:", exception);
			resultError = ExceptionMsgConst.MSG_DELETE_FAILED_REFERENCED;
		} else if (exception instanceof IllegalArgumentException) {
//			log.error("业务方法执行异常:", exception);
			resultError = ExceptionMsgConst.MSG_ILLEGAL_ARGUMENT;
		}
		if(StringUtils.isBlank(resultError))resultError = "未知异常";
		return resultError;
	}
    
    protected final class ExceptionMsgConst {

		public static final String	MSG_DELETE_FAILED_REFERENCED	= "删除失败，该条记录被引用";

		public static final String	MSG_INSERT_FAILED_NOPARENT		= "添加失败，引用记录不存在";

		public static final String	MSG_INSERT_FAILED_NOTUNIQUE		= "添加失败，相同记录已存在";

		public static final String	MSG_FAILED_OTHER				= "数据存取失败，请检查数据正确性";

		public static final String	MSG_ILLEGAL_ARGUMENT			= "参数不合法";
	}
}
