package com.qmth.themis.common.exception;

import com.alibaba.fastjson.JSONObject;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.util.Result;
import com.qmth.themis.common.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * @Description: 全局异常处理
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2019/10/11
 */
@ControllerAdvice
public class GlobalDefultExceptionHandler {

    private final static Logger log = LoggerFactory.getLogger(GlobalDefultExceptionHandler.class);

    /**
     * excetion异常处理
     *
     * @param e
     * @param request
     * @param response
     * @param <T>
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public <T> Result defultExcepitonHandler(Exception e, HttpServletRequest request, HttpServletResponse response) {
        StringJoiner stringJoiner = new StringJoiner("");
        if (e instanceof BusinessException) {
            BusinessException businessException = (BusinessException) e;
            response.setStatus(businessException.getCode());
            try {
                stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
                stringJoiner.add("[status]:").add(String.valueOf(businessException.getStatusCode())).add("\r\n");
                stringJoiner.add("[code]:").add(String.valueOf(businessException.getCode())).add("\r\n");
                stringJoiner.add("[message]:").add(businessException.getMessage());
                log.error("请求出错:{}", stringJoiner.toString());
            } catch (Exception e1) {
            }
            return ResultUtil.error(businessException.getStatusCode(), businessException.getMessage());
        } else if (e instanceof IllegalArgumentException) {
            response.setStatus(ExceptionResultEnum.EXCEPTION_ERROR.getCode());
            String errorMessage = "暂不支持此平台";
            if (e.getMessage().contains("No enum constant com.qmth.themis.common.enums.Platform")) {
                try {
                    stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
                    stringJoiner.add("[status]:").add(String.valueOf(ExceptionResultEnum.EXCEPTION_ERROR.getStatusCode())).add("\r\n");
                    stringJoiner.add("[code]:").add(String.valueOf(ExceptionResultEnum.EXCEPTION_ERROR.getCode())).add("\r\n");
                    stringJoiner.add("[message]:").add(errorMessage);
                    log.error("请求出错:{}", stringJoiner.toString());
                } catch (Exception e1) {
                }
                return ResultUtil.error(ExceptionResultEnum.EXCEPTION_ERROR.getStatusCode(), errorMessage);
            }
        } else if (e instanceof MethodArgumentNotValidException) {
            response.setStatus(ExceptionResultEnum.EXCEPTION_ERROR.getCode());
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            List<String> errorList = bindingResult.getFieldErrors().stream().map(o -> o.getDefaultMessage()).collect(Collectors.toList());
            String errorMessage = JSONObject.toJSONString(errorList);
            try {
                stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
                stringJoiner.add("[status]:").add(String.valueOf(ExceptionResultEnum.ERROR.getStatusCode())).add("\r\n");
                stringJoiner.add("[code]:").add(String.valueOf(ExceptionResultEnum.ERROR.getCode())).add("\r\n");
                stringJoiner.add("[message]:").add(errorMessage);
                log.error("请求出错:{}", stringJoiner.toString());
            } catch (Exception e1) {
            }
            return ResultUtil.error(ExceptionResultEnum.ERROR.getCode(), errorMessage);
        }
        response.setStatus(ExceptionResultEnum.EXCEPTION_ERROR.getCode());
        try {
            stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
            stringJoiner.add("[status]:").add(String.valueOf(ExceptionResultEnum.EXCEPTION_ERROR.getStatusCode())).add("\r\n");
            stringJoiner.add("[code]:").add(String.valueOf(ExceptionResultEnum.EXCEPTION_ERROR.getCode())).add("\r\n");
            stringJoiner.add("[message]:").add(e.getMessage());
            log.error("请求出错:{}", stringJoiner.toString());
        } catch (Exception e1) {
        }
        return ResultUtil.error(ExceptionResultEnum.EXCEPTION_ERROR.getStatusCode(), e.getMessage());
    }

    /**
     * sql异常处理
     *
     * @param e
     * @param request
     * @param response
     * @param <T>
     * @return
     */
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public <T> Result sqlExceptionHandler(SQLException e, HttpServletRequest request, HttpServletResponse response) {
        response.setStatus(ExceptionResultEnum.SQL_ERROR.getCode());
        try {
            StringJoiner stringJoiner = new StringJoiner("");
            stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
            stringJoiner.add("[status]:").add(String.valueOf(ExceptionResultEnum.SQL_ERROR.getStatusCode())).add("\r\n");
            stringJoiner.add("[code]:").add(String.valueOf(ExceptionResultEnum.SQL_ERROR.getCode())).add("\r\n");
            stringJoiner.add("[message]:").add(e.getMessage());
            log.error("请求出错:{}", stringJoiner.toString());
        } catch (Exception e1) {
        }
        return ResultUtil.error(ExceptionResultEnum.SQL_ERROR.getStatusCode(), e.getMessage());
    }

    /**
     * 反射异常处理
     *
     * @param e
     * @param request
     * @param response
     * @param <T>
     * @return
     */
    @ExceptionHandler(InvocationTargetException.class)
    @ResponseBody
    public <T> Result invocationTargetExceptionHandler(InvocationTargetException e, HttpServletRequest request, HttpServletResponse response) {
        response.setStatus(ExceptionResultEnum.INVOCATIONTARGET_ERROR.getCode());
        try {
            StringJoiner stringJoiner = new StringJoiner("");
            stringJoiner.add("[error path]:").add(request.getServletPath()).add("\r\n");
            stringJoiner.add("[status]:").add(String.valueOf(ExceptionResultEnum.INVOCATIONTARGET_ERROR.getStatusCode())).add("\r\n");
            stringJoiner.add("[code]:").add(String.valueOf(ExceptionResultEnum.INVOCATIONTARGET_ERROR.getCode())).add("\r\n");
            stringJoiner.add("[message]:").add(ExceptionResultEnum.INVOCATIONTARGET_ERROR.name() + e.getTargetException());
            log.error("请求出错:{}", stringJoiner.toString());
        } catch (Exception e1) {
        }
        return ResultUtil.error(ExceptionResultEnum.INVOCATIONTARGET_ERROR.getStatusCode(),
                ExceptionResultEnum.INVOCATIONTARGET_ERROR.name() + e.getTargetException());
    }
}
