/* (C) 2021 YiRing, Inc. */
package com.yiring.common.core;

import com.yiring.common.exception.FailStatusException;
import lombok.Getter;
import org.jetbrains.annotations.PropertyKey;
import org.springframework.lang.Nullable;

/**
 * API 响应状态码
 * 包含系统和业务两个维度
 *
 * @author ifzm
 */

@SuppressWarnings({ "unused" })
public enum Status {
    /**
     * 成功
     */
    OK(200, "Status.OK"),

    /**
     * 用户认证失败
     */
    NON_AUTHORITATIVE_INFORMATION(203, "Status.NON_AUTHORITATIVE_INFORMATION"),

    /**
     * 失败的请求，通常是一些验证错误
     */
    BAD_REQUEST(400, "Status.BAD_REQUEST"),

    /**
     * 鉴权失败
     */
    UNAUTHORIZED(401, "Status.UNAUTHORIZED"),

    /**
     * 禁止访问（可能是二级认证失败）
     */
    FORBIDDEN(403, "Status.FORBIDDEN"),

    /**
     * 找不到资源
     */
    NOT_FOUND(404, "Status.NOT_FOUND"),

    /**
     * 不支持的请求类型
     */
    METHOD_NOT_ALLOWED(405, "Status.METHOD_NOT_ALLOWED"),

    /**
     * 参数校验失败
     */
    EXPECTATION_FAILED(417, "Status.EXPECTATION_FAILED"),

    /**
     * 请求过于频繁
     */
    TOO_MANY_REQUESTS(429, "Status.TOO_MANY_REQUESTS"),

    /**
     * 服务器错误
     */
    INTERNAL_SERVER_ERROR(500, "Status.INTERNAL_SERVER_ERROR"),

    /**
     * 未知错误
     */
    UNKNOWN_ERROR(500, "Status.UNKNOWN_ERROR"),

    /**
     * API 未实现
     */
    NOT_IMPLEMENTED(501, "Status.NOT_IMPLEMENTED"),

    /**
     * 服务异常（网关提醒）
     */
    BAD_GATEWAY(502, "Status.BAD_GATEWAY"),

    /**
     * 服务暂停（网关提醒）
     */
    SERVICE_UNAVAILABLE(503, "Status.SERVICE_UNAVAILABLE");

    private final int value;

    /**
     * -- GETTER --
     *  Return the reason phrase of this status code.
     */
    @Getter
    private final String reasonPhrase;

    Status(int value, @PropertyKey(resourceBundle = "i18n.status") String reasonPhrase) {
        this.value = value;
        this.reasonPhrase = reasonPhrase;
    }

    /**
     * Return the enum constant of this type with the specified numeric value.
     *
     * @param statusCode the numeric value of the enum to be returned
     * @return the enum constant with the specified numeric value
     * @throws IllegalArgumentException if this enum has no constant for the specified numeric value
     */
    public static Status valueOf(int statusCode) {
        Status status = resolve(statusCode);
        if (status == null) {
            throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
        }
        return status;
    }

    /**
     * Resolve the given status code to an {@code ResultStatus}, if possible.
     *
     * @param statusCode the HTTP status code (potentially non=standard)
     * @return the corresponding {@code ResultStatus}, or {@code null} if not found
     * @since 5.0
     */
    @Nullable
    public static Status resolve(int statusCode) {
        for (Status status : values()) {
            if (status.value == statusCode) {
                return status;
            }
        }
        return null;
    }

    /**
     * Return the integer value of this status code.
     */
    public int value() {
        return this.value;
    }

    /**
     * Return a string representation of this status code.
     */
    @Override
    public String toString() {
        return this.value + " " + name();
    }

    /**
     * 快速失败异常
     */
    public FailStatusException exception() {
        return exception(null);
    }

    /**
     * 快速失败异常
     *
     * @param message 异常消息
     */
    public FailStatusException exception(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) {
        return new FailStatusException(this, message);
    }

    /**
     * 暴露异常
     *
     * @param message 异常消息
     */
    public void expose(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) throws FailStatusException {
        throw exception(message);
    }
}
