package tech.easyflow.common.web.exceptions;

/**
 * 可安全返回给客户端的业务异常。
 *
 * <p>业务异常默认使用 HTTP 400。需要表达冲突、无权限、资源不存在等语义时，
 * 调用方应通过带状态码的构造函数显式指定 HTTP 状态和稳定业务错误码。</p>
 */
public class BusinessException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    private final int httpStatus;
    private final int errorCode;

    /**
     * 创建默认的 HTTP 400 业务异常。
     */
    public BusinessException() {
        this(400, 1, "请求处理失败");
    }

    /**
     * 创建默认的 HTTP 400 业务异常。
     *
     * @param msg 可安全展示给客户端的错误消息
     */
    public BusinessException(String msg) {
        this(400, 1, msg);
    }

    /**
     * 创建带 HTTP 状态和业务错误码的业务异常。
     *
     * @param httpStatus HTTP 状态码，必须为 400 到 599
     * @param errorCode 稳定业务错误码，不能为成功码 0
     * @param msg 可安全展示给客户端的错误消息
     * @throws IllegalArgumentException 状态码或业务错误码不合法时抛出
     */
    public BusinessException(int httpStatus, int errorCode, String msg) {
        this(httpStatus, errorCode, msg, null);
    }

    /**
     * 创建带 HTTP 状态、业务错误码和根因的业务异常。
     *
     * @param httpStatus HTTP 状态码，必须为 400 到 599
     * @param errorCode 稳定业务错误码，不能为成功码 0
     * @param msg 可安全展示给客户端的错误消息
     * @param cause 原始失败根因
     * @throws IllegalArgumentException 状态码或业务错误码不合法时抛出
     */
    public BusinessException(int httpStatus, int errorCode, String msg, Throwable cause) {
        super(requireMessage(msg), cause);
        if (httpStatus < 400 || httpStatus > 599) {
            throw new IllegalArgumentException("HTTP 状态码必须位于 400 到 599 之间");
        }
        if (errorCode == 0) {
            throw new IllegalArgumentException("业务错误码不能为成功码 0");
        }
        this.httpStatus = httpStatus;
        this.errorCode = errorCode;
    }

    /**
     * 获取应返回的 HTTP 状态码。
     *
     * @return HTTP 状态码
     */
    public int getHttpStatus() {
        return httpStatus;
    }

    /**
     * 获取稳定业务错误码。
     *
     * @return 业务错误码
     */
    public int getErrorCode() {
        return errorCode;
    }

    /**
     * 归一化可安全返回给客户端的错误消息。
     *
     * @param message 原始消息
     * @return 非空安全消息
     */
    private static String requireMessage(String message) {
        return message == null || message.isBlank() ? "请求处理失败" : message;
    }
}
