package com.lcrx.selector.exception;

import com.lcrx.selector.utils.result.Result;
import com.lcrx.selector.utils.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * 全局异常处理
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @Value("${applicationSettings.includeStackTrace}")
    private Boolean includeStackTrace;


    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(RuntimeException e){
        log.error(logPrefix(ResultCode.UNKNOWN), e);
        return getResult(ResultCode.SYS,getMsg(e.getMessage(),ResultCode.UNKNOWN),getStackTrace(e));
    }


    @ExceptionHandler(AuthorityException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(AuthorityException e){
        log.error(logPrefix(ResultCode.AUTHORITY), e);
        return getResult(ResultCode.AUTHORITY,getMsg(e.getMessage(),ResultCode.AUTHORITY),getStackTrace(e));
    }


    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(BusinessException e){
        log.error(logPrefix(ResultCode.BUSINESS), e);
        return getResult(ResultCode.BUSINESS,getMsg(e.getMessage(),ResultCode.BUSINESS),getStackTrace(e));
    }


    @ExceptionHandler(DataException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(DataException e){
        log.error(logPrefix(ResultCode.DATA), e);
        return getResult(ResultCode.DATA,getMsg(e.getMessage(),ResultCode.DATA),getStackTrace(e));
    }


    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(ServiceException e){
        log.error(logPrefix(ResultCode.SERVICE), e);
        return getResult(ResultCode.SERVICE,getMsg(e.getMessage(),ResultCode.SERVICE),getStackTrace(e));
    }


    @ExceptionHandler(SysException.class)
    @ResponseBody
    public Result<Void> runtimeHandler(SysException e){
        log.error(logPrefix(ResultCode.SYS), e);
        return getResult(ResultCode.SYS,getMsg(e.getMessage(),ResultCode.SYS),getStackTrace(e));
    }


    private String logPrefix(ResultCode resultCode){
        return "【" + resultCode.getMsg() + "】: ";
    }

    private Result<Void> getResult(ResultCode resultCode, String msg, String trace){
        if (includeStackTrace) {
            return Result.genResult(resultCode.getCode(),msg,trace);
        }
        return Result.genResult(resultCode.getCode(),msg);
    }


    private String getMsg(String eMessage,ResultCode resultCode){
        String msg = "";
        if (eMessage != null) {
            int index = eMessage.indexOf(':');
            msg = index != -1 ? eMessage.substring(index + 1).trim() : eMessage;
        }
        return resultCode == null ? msg : logPrefix(resultCode) + msg;
    }

    private String getStackTrace(Throwable error) {
        StringWriter stackTrace = new StringWriter();
        error.printStackTrace(new PrintWriter(stackTrace));
        stackTrace.flush();
        return stackTrace.toString();
    }
}
