package com.yifu.cloud.plus.v1.yifu.common.security.exception;

import com.baomidou.lock.exception.LockFailureException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.yifu.cloud.plus.v1.yifu.common.core.exception.ValidateCodeException;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 全局的的异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
	
	/**
	 * description:获取用户账号
	 *
	 * @Param: []
	 * @Return: java.lang.String
	 * @Author: pwang
	 * @Date: 2020/7/30
	 */
	public String getUsername() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			return null;
		}
		return authentication.getName();
	}
	/**
	 * 全局异常.
	 *
	 * @param e the e
	 * @return R
     * 带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析。可以实现自定义的一些异常,同时在页面上进行显示
     * @ExceptionHandler:当这个Controller中任何一个方法发生异常，一定会被这个方法拦截到
	 */
	@ExceptionHandler(Exception.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ResponseBody
	public R exception(Exception e) {
		errorLog( e );
		if( null != e.getMessage()){
			return  R.failed(e,e.getMessage());
		}else{
			return  R.failed(e,"系统异常！");
		}
	}

	@ExceptionHandler({HttpMessageNotReadableException.class})
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R notReadableException(Exception e) {
		errorLog( e );
		if( null != e.getMessage()){
			return  R.failed("数据参数解析异常！",e.getMessage());
		}else{
			return  R.failed(e,"数据参数解析异常！");
		}
	}


	@ExceptionHandler({NumberFormatException.class, InvalidFormatException.class})
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R formatException(Exception e) {
		errorLog( e );
		if( null != e.getMessage()){
			return  R.failed("数据格转换异常！",e.getMessage());
		}else{
			return  R.failed(e,"数据格转换异常！");
		}
	}

	/**
	 * validation Exception
	 *
	 * @param exception
	 * @return R
	 */
	@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class, })
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public R bodyValidExceptionHandler(MethodArgumentNotValidException exception) {
		List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
		R result =  R.failed("数据验证出错:".concat(fieldErrors.get(0).getDefaultMessage()));
		errorLog(exception);
		return result;
	}
	/**
	 * validation Exception
	 *
	 * @param exception
	 * @return R
	 */
	@ExceptionHandler({ ConstraintViolationException.class})
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public R bodyValidExceptionHandler(ConstraintViolationException exception) {
		Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
		String mess = exception.getMessage();
		if(Common.isEmpty(constraintViolations)){
			for(ConstraintViolation constraintViolation:constraintViolations){
				mess  =  constraintViolation.getMessage();
				break;
			}
		}
		R result =  R.failed("数据验证出错:".concat(mess));
		errorLog(exception);
		return result;
	}



	/**
	 * 数据异常 Exception
	 *
	 * @param  e
	 * @return R
	 */
	@ExceptionHandler({ValidateCodeException.class, DataException.class})
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public R dataExceptionHandler(Exception e) {
		errorLog(e);
		R result =  R.failed("数据异常："+ e.getMessage());
		return result;
	}
    /**
     * 异常打印的方法
     * @Author pwang
     * @Date 2020-07-30 15:14
     * @param exception
     * @return
     **/
	private void errorLog(Exception exception) {
		try {
			log.error("全局异常信息 触发用户：{}  ex={}", getUsername(), exception.getMessage(), exception);
		}catch (Exception e){
			log.error("全局异常信息 触发用户：获取失败  ex={}",  exception.getMessage(), exception);
		}
	}
	/**
	 * 获取锁异常 lockException
	 *
	 * @param  e
	 * @return R
	 */
	@ExceptionHandler({LockFailureException.class})
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R lockFailExceptionHandler(Exception e) {
		errorLog(e);
		R result =  R.failed("业务处理锁异常："+ e.getMessage());
		return result;
	}
}
