package cn.quantgroup.xyqb.controller;

import cn.quantgroup.xyqb.exception.*;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.util.IpUtil;
import cn.quantgroup.xyqb.exception.ResubmissionException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * Created by Miraculous on 15/7/6.
 * 出现异常，进入这个handler。
 */
@Slf4j
@ControllerAdvice
@RestController
public class ExceptionHandlingController implements IBaseController {

    private static final JsonResult EXCEPTION_RESULT = new JsonResult("服务出错。", (long) HttpStatus.INTERNAL_SERVER_ERROR.value(), null);

    /**
     * 密码错误次数达到上限异常
     *
     * @param vce
     * @return
     */
    @ExceptionHandler(PasswordErrorLimitException.class)
    public JsonResult passwordErrorLimitException(PasswordErrorLimitException vce) {
        log.info("throw PasswordErrorLimitException,msg={},businessCode={}, clientIp={}", vce.getMessage(), 2L, IpUtil.getRemoteIP(getRequest()));
        return JsonResult.buildErrorStateResult(vce.getMessage(), null, 2L);
    }

    /**
     * 短信验证码错误或失效异常
     *
     * @param vce
     * @return
     */
    @ExceptionHandler(VerificationCodeErrorException.class)
    public JsonResult verificationCodeErrorException(VerificationCodeErrorException vce) {
        log.info("throw VerificationCodeErrorException,msg={},businessCode={}, clientIp={}", vce.getMessage(), 1L, IpUtil.getRemoteIP(getRequest()));
        return JsonResult.buildErrorStateResult(vce.getMessage(), null, 1L);
    }

    /**
     * 用户不存在异常
     *
     * @param unee
     * @return
     */
    @ExceptionHandler(UserNotExistException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public JsonResult userNotExistException(UserNotExistException unee) {
        log.info("throw UserNotExistException,msg={},businessCode={},code={}", unee.getMessage(), 1L, (long) HttpStatus.UNAUTHORIZED.value());
        return new JsonResult(unee.getMessage(), (long) HttpStatus.UNAUTHORIZED.value(), null);
    }

    /**
     * 用户查询或导出异常
     *
     * @param uqle
     * @return
     */
    @ExceptionHandler(UserQueryLogException.class)
    public JsonResult userQueryLogException(UserQueryLogException uqle) {
        log.info("throw UserQueryLogException,msg={},businessCode={},code={}", uqle.getMessage(), 1L, 0L);
        return JsonResult.buildErrorStateResult(uqle.getMessage(), null);
    }

    /**
     * 微信关联异常
     *
     * @param wrue
     * @return
     */
    @ExceptionHandler(WechatRelateUserException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public JsonResult wechatRelateUserException(WechatRelateUserException wrue) {
        log.info("throw WechatRelateUserException,msg={},businessCode={},code={}", wrue.getMessage(), 1L, (long) HttpStatus.UNAUTHORIZED.value());
        return new JsonResult(wrue.getMessage(), (long) HttpStatus.UNAUTHORIZED.value(), null);
    }

    /**
     * 其他全局异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public JsonResult exceptionOccurs(Exception e) {
        HttpServletRequest request = getRequest();
        String uri = request.getRequestURI();
        String registerFrom = request.getParameter("registerFrom");
        log.error("[exception][global_exception]接口异常 URI:{}, registerFrom:{},error={}", uri, registerFrom, e);
        return EXCEPTION_RESULT;
    }

    @ExceptionHandler(ValidationException.class)
    public JsonResult validException(ValidationException exception) {
        ConstraintViolationException exs = (ConstraintViolationException) exception;
        Set<ConstraintViolation<?>> constraintViolations = exs.getConstraintViolations();
        if (constraintViolations.isEmpty()) {
            log.error("这里出了个错....", exception.getMessage());
            return null;
        }
        String message = constraintViolations.iterator().next().getMessage();
        return JsonResult.buildErrorStateResult(message, null);
    }

    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleBindException(Exception e) {
        BindingResult result = null;
        if (e instanceof MethodArgumentNotValidException) {
            result = ((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException) {
            result = ((BindException) e).getBindingResult();
        }
        if (result != null) {
            List<ObjectError> errors = result.getAllErrors();
            StringBuilder sb = new StringBuilder();
            if (errors != null && errors.size() > 0) {
                Iterator<ObjectError> iterator = errors.iterator();
                ObjectError err = null;
                while ((err = iterator.next()) != null) {
                    sb.append(err.getDefaultMessage());
                    if (iterator.hasNext()) {
                        sb.append("; ");
                    } else {
                        sb.append("。");
                        break;
                    }
                }
            }
            return JsonResult.buildErrorStateResult(sb.toString(), null);
        }
        return null;
    }

    @ExceptionHandler({DataException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleDataException(DataException e) {
        return JsonResult.buildErrorStateResult(e.getMessage(), null);
    }
    @ExceptionHandler({AppletException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleAppletException(AppletException e) {
        return JsonResult.buildErrorResultWhithCode(e.getMessage(), e.getCode());
    }

    @ExceptionHandler(BadSqlGrammarException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleBadSqlGrammarException(BadSqlGrammarException e) {
        log.error("sql语法解析异常 error sql = 【{}】", e.getSql(), e);
        return JsonResult.buildErrorStateResult("参数错误。", null);
    }

    @ExceptionHandler(ResubmissionException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public JsonResult resubmissionException(ResubmissionException re) {
        return JsonResult.buildErrorStateResult(re.getMessage(), null);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public JsonResult handelMissingServletRequestParameterException(MissingServletRequestParameterException re) {
        return JsonResult.buildErrorStateResult(re.getMessage(), null);
    }

    /**
     * 用户注册登录异常处理
     * @param e 异常
     * @return JsonResult<String>
     */
    @ExceptionHandler(UserRegisterLoginException.class)
    public JsonResult<?> handleUserDeregisterException(UserRegisterLoginException e) {
        return JsonResult.buildErrorStateResult(e.getMessage(), null);
    }

    @ExceptionHandler(AccessForbiddenException.class)
    public JsonResult<?> handleAccessForbiddenException(AccessForbiddenException e) {
        return JsonResult.buildErrorStateResult(e.getMessage(), null);
    }
}
