package com.dhcc.finance.controller.advice;

import java.util.List;
import java.util.Set;

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

import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
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 com.dhcc.common.RestStatus;
import com.dhcc.common.constant.SysConstants;
import com.dhcc.common.constant.SysStatusCode;
import com.dhcc.common.exception.IllegalValidateException;
import com.dhcc.common.exception.RestStatusException;
import com.dhcc.common.model.CurrencyMeta;
import com.dhcc.common.model.response.ErrorResponse;
import com.dhcc.common.util.RestStatusUtil;
import com.google.common.collect.ImmutableMap;

import lombok.extern.slf4j.Slf4j;

@ControllerAdvice
@Slf4j
public class FaultBarrier {
    private static final ImmutableMap<Class<? extends Throwable>, RestStatus> EXCEPTION_MAPPINGS;

    static {
        final ImmutableMap.Builder<Class<? extends Throwable>, RestStatus> builder = ImmutableMap.builder();
        builder.put(Exception.class, SysStatusCode.SERVER_UNKNOWN_ERROR); /*其他未被发现的异常*/
        EXCEPTION_MAPPINGS = builder.build();
    }


    @ResponseBody
    @ExceptionHandler(Exception.class)
    public ErrorResponse<Object,CurrencyMeta> exception(Exception e, HttpServletRequest request) {
        log.error("request id: {}\r\nexception: {}",request.getAttribute(SysConstants.REQUEST_ATTRIBUTE.REQUEST_ID), e);
        final ErrorResponse<Object,CurrencyMeta> error;
        if (e instanceof NullPointerException) {
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_NULL_EXCEPTION,e.getMessage(),new CurrencyMeta());
        }else if(e instanceof BindException) {//MethodArgumentNotValidException
            StringBuilder sb = new StringBuilder();
            FieldError fieldError = ((BindException)e).getFieldError();
            sb.append(fieldError.getDefaultMessage());
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_ERROR,sb.toString(),e.getMessage(),new CurrencyMeta());
        }else if(e instanceof MethodArgumentNotValidException) {//MethodArgumentNotValidException
            StringBuilder sb = new StringBuilder();
            BindingResult bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
            FieldError fieldError = bindingResult.getFieldError();
            sb.append(fieldError.getDefaultMessage());
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_ERROR,sb.toString(),e.getMessage(),new CurrencyMeta());
        } else if (e instanceof HttpMessageNotReadableException) {
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_NOT_READABLE,e.getMessage(),new CurrencyMeta());
        } else if(e instanceof RestStatusException){
            RestStatus status = RestStatusUtil.getEnumByKey(e.getMessage());
            if(status != null) {
                error = new ErrorResponse<Object,CurrencyMeta>(status,new CurrencyMeta());
            }else {
                error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_UNKNOWN_ERROR,new CurrencyMeta());
            }
        } else if(e instanceof IllegalValidateException){
            //Hibernate Validator的校验异常
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_ERROR,e.getMessage(),new CurrencyMeta());
        } else if(e instanceof ConstraintViolationException){
            //Hibernate Validator的校验异常
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_CHECK_ERROR,e.getMessage(),e.getMessage(),new CurrencyMeta());
        } else{
            //未知异常
            error = new ErrorResponse<Object,CurrencyMeta>(SysStatusCode.SERVER_UNKNOWN_ERROR,e.getMessage(),new CurrencyMeta());
        }
        return error;   
    }

}
