package com.scpyun.base.servlet.advice;

import com.scpyun.base.core.exception.BaseExceptionConstant;
import com.scpyun.base.core.exception.CustomException;
import com.scpyun.base.core.utils.Global;
import com.scpyun.base.core.utils.UnifyLogger;
import com.scpyun.base.servlet.bean.ErrorInfo;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestControllerAdvice
public class GlobalExceptionAdvisor {

	public static final String TABLE_NOT_EXIST_SUFFIX = "' doesn't exist";
	public static final String COLUMN_NOT_EXIST_PREFIX = "Unknown column '";
	public static final String COLUMN_NOT_EXIST_PATTERN = COLUMN_NOT_EXIST_PREFIX + "([\\s\\S]*?)' in 'field list'";
	public static final String TABLE_DATA_DEFAULT_VALUE_PREFIX = "doesn't have a default value";
	public static final String TABLE_NOT_EXIST_PATTERN = "Table '([\\s\\S]*?)' doesn't exist";
	public static final String TABLE_DEFAULT_VALUE_PREFIX = "Field '([\\s\\S]*?)' doesn't have a default value";
	public static final Pattern TABLE_DEFAULT_VALUE_PREFIX_PATTERN =  Pattern.compile(TABLE_DEFAULT_VALUE_PREFIX);
	public static final Pattern TABLE_PATTERN = Pattern.compile(TABLE_NOT_EXIST_PATTERN);
	public static final Pattern COLUMN_PATTERN = Pattern.compile(COLUMN_NOT_EXIST_PATTERN);


	@ExceptionHandler(value = CustomException.class)
	public ErrorInfo<Object> customErrorHandler(HttpServletRequest req, Exception e) throws Exception {
		CustomException ex = (CustomException)e;
		if(ex.hasCause()){
			UnifyLogger.parentException(ex);
		}else{
			UnifyLogger.parentException(ex,400);
		}
		if(ex.getCode() >= 10000){
//			return getErrorInfo(ex.getCode(),"内部错误",req.getRequestURL().toString());
			return getErrorInfo(ex.getCode(),ex.getMsg(),req.getRequestURL().toString());
		}else if(ex.getCode() >= 1000){
			return getErrorInfo(ex.getCode(),ex.getMsg(),req.getRequestURL().toString());
		}else{
			return getErrorInfo(ex.getCode(),ex.getMsg(),req.getRequestURL().toString());
		}
	}


	/**
	 * @param exceptionType 异常类型 class.name
	 * @param badSqlString 异常信息
	 * @param url 异常url地址
	 * @return
	 */
	public static ErrorInfo<Object> badSqlExceptionHandler(String exceptionType, String badSqlString, String url) {
		switch (exceptionType) {
			case "org.springframework.jdbc.BadSqlGrammarException":
				if (badSqlString.contains(COLUMN_NOT_EXIST_PREFIX)) {
					Matcher m = COLUMN_PATTERN.matcher(badSqlString);
					while (m.find()) {
						return getErrorInfo(BaseExceptionConstant.API_ERROR, "数据库数据表数据字段不存在！字段名：" + m.group(1),
								url);
					}
				}
				if (badSqlString.contains(TABLE_NOT_EXIST_SUFFIX)) {
					Matcher m = TABLE_PATTERN.matcher(badSqlString);
					while (m.find()) {
						return getErrorInfo(BaseExceptionConstant.API_ERROR, "数据库数据表不存在！数据表：" + m.group(1),
								url);
					}
				}
				return getErrorInfo(BaseExceptionConstant.API_ERROR, badSqlString,
						url);
			case "org.springframework.dao.DataIntegrityViolationException":
				if (badSqlString.contains(TABLE_DATA_DEFAULT_VALUE_PREFIX)) {
					Matcher m = TABLE_DEFAULT_VALUE_PREFIX_PATTERN.matcher(badSqlString);
					while (m.find()) {
						return getErrorInfo(BaseExceptionConstant.API_ERROR, "数据字段不能为‘空’！字段名：" + m.group(1),
								url);
					}
				}
				return getErrorInfo(BaseExceptionConstant.API_ERROR, badSqlString,
						url);
			case "org.springframework.web.HttpRequestMethodNotSupportedException":
				return getErrorInfo(BaseExceptionConstant.API_ERROR, "请求方式错误", url);
			case "org.springframework.web.servlet.NoHandlerFoundException":
				return getErrorInfo(BaseExceptionConstant.API_ERROR, "请求地址错误", url);
			case "org.springframework.web.bind.MissingServletRequestParameterException":
				return getErrorInfo(BaseExceptionConstant.API_ERROR, "请求参数错误", url);
			case "org.springframework.dao.DuplicateKeyException":
				return getErrorInfo(BaseExceptionConstant.INDEX_CONFLICT, "保存失败，重复!", url);
			default:
				return getErrorInfo(BaseExceptionConstant.API_ERROR, badSqlString, url);
		}
	}

	@ExceptionHandler(value = Exception.class)
	@Order(value=0)
	public ErrorInfo<Object> defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        e.printStackTrace();
		UnifyLogger.parentException(e);
		if ("prod".equals(Global.getConfig("server.enviro"))) {
			return defaultErrorHandlerByNetworkError(req);
		}
		try {
			return badSqlExceptionHandler(e.getClass().getName(), e.getMessage(), req.getRequestURL().toString());
		}catch (Exception ee) {
			return getErrorInfo(BaseExceptionConstant.API_ERROR, ee.getMessage(),
					req.getRequestURL().toString());
		}
	}

	public ErrorInfo<Object> defaultErrorHandlerByNetworkError(HttpServletRequest req) throws Exception {
		return getErrorInfo(BaseExceptionConstant.API_ERROR, "网络延迟，请稍后重试！", req.getRequestURL().toString());
	}

	@ExceptionHandler(NoHandlerFoundException.class)
//	@ResponseStatus(HttpStatus.NOT_FOUND)
	public void to404ErrorHandle(HttpServletRequest req, HttpServletResponse rsp, Exception e) {
		return;
	}


	public static ErrorInfo<Object> getErrorInfo(int errcode,String errmsg,String url){
		ErrorInfo<Object> r = new ErrorInfo<Object>();
		r.setErrmsg(errmsg);
		r.setErrcode(errcode);
		r.setUrl(url);
		return r;
	}

}


