#ifndef SLED_UTILITY_STATUS_H
#define SLED_UTILITY_STATUS_H

#pragma once
#include "sled/utility/slice.h"
#include <string>

namespace sled {
class Status {
    enum Code {
        kOk                = 0,
        kInvalidArgument   = 1,
        kOutOfRange        = 2,
        kUnathenticated    = 3,
        kPermissionDenied  = 4,
        kNotFound          = 5,
        kAborted           = 6, // 操作被中断
        kAlreadyExists     = 7, // 资源已存在
        kResourceExhausted = 8, // 资源配额不足或速率限制
        kCancelled         = 9, // 请求给客户端取消
        kDataLoss          = 10,// 数据损坏或丢失
        kUnknown           = 11,// 未知的内部错误
        kInternal          = 12,// 内部错误
        kNotImplemented    = 13,// API 未实现
        kUnavailable       = 14,// 服务不可用
        kDeadlineExceeded  = 15,// 执行超时
                                // kNotSupported = 3,
                                // kIOError = 5,
    };

    struct State {
        Code code = kOk;
        std::string message;
    };

public:
    Status() noexcept {}

    ~Status() {}

    Status(const Status &rhs);
    Status &operator=(const Status &rhs);

    Status(Status &&rhs) noexcept
    {
        state_.code    = rhs.state_.code;
        state_.message = std::move(rhs.state_.message);
    }

    Status &operator=(Status &&rhs) noexcept;
    std::string ToString() const;

#define DUST_STATUS_DECLARE_CREATER(name)                                                                              \
    static Status name(const Slice &msg, const Slice &msg2 = Slice()) { return Status(k##name, msg, msg2); }
#define DUST_STATUS_DECLARE_IS(name)                                                                                   \
    bool Is##name() const { return code() == k##name; }

    static Status OK() { return Status(); }
    DUST_STATUS_DECLARE_CREATER(InvalidArgument)
    DUST_STATUS_DECLARE_CREATER(OutOfRange)
    DUST_STATUS_DECLARE_CREATER(Unathenticated)
    DUST_STATUS_DECLARE_CREATER(PermissionDenied)
    DUST_STATUS_DECLARE_CREATER(NotFound)
    DUST_STATUS_DECLARE_CREATER(Aborted)
    DUST_STATUS_DECLARE_CREATER(AlreadyExists)
    DUST_STATUS_DECLARE_CREATER(ResourceExhausted)
    DUST_STATUS_DECLARE_CREATER(Cancelled)
    DUST_STATUS_DECLARE_CREATER(DataLoss)
    DUST_STATUS_DECLARE_CREATER(Unknown)
    DUST_STATUS_DECLARE_CREATER(Internal)
    DUST_STATUS_DECLARE_CREATER(NotImplemented)
    DUST_STATUS_DECLARE_CREATER(Unavailable)
    DUST_STATUS_DECLARE_CREATER(DeadlineExceeded)

    bool ok() const { return state_.code == kOk; }
    DUST_STATUS_DECLARE_IS(InvalidArgument)
    DUST_STATUS_DECLARE_IS(OutOfRange)
    DUST_STATUS_DECLARE_IS(Unathenticated)
    DUST_STATUS_DECLARE_IS(PermissionDenied)
    DUST_STATUS_DECLARE_IS(NotFound)
    DUST_STATUS_DECLARE_IS(Aborted)
    DUST_STATUS_DECLARE_IS(AlreadyExists)
    DUST_STATUS_DECLARE_IS(ResourceExhausted)
    DUST_STATUS_DECLARE_IS(Cancelled)
    DUST_STATUS_DECLARE_IS(DataLoss)
    DUST_STATUS_DECLARE_IS(Unknown)
    DUST_STATUS_DECLARE_IS(Internal)
    DUST_STATUS_DECLARE_IS(NotImplemented)
    DUST_STATUS_DECLARE_IS(Unavailable)
    DUST_STATUS_DECLARE_IS(DeadlineExceeded)

#undef DUST_STATUS_DECLARE_CREATER
#undef DUST_STATUS_DECLARE_IS

private:
    Status(Code code, const Slice &msg, const Slice &msg2);

    Code code() const { return state_.code; }

    Status(Code code);

    State state_;
};

inline Status::Status(const Status &rhs)
{
    state_.code    = rhs.state_.code;
    state_.message = rhs.state_.message;
}

inline Status &
Status::operator=(const Status &rhs)
{
    state_.code    = rhs.state_.code;
    state_.message = rhs.state_.message;
    return *this;
}

inline Status &
Status::operator=(Status &&rhs) noexcept
{
    if (&rhs == this) { return *this; }

    state_.code    = rhs.state_.code;
    state_.message = std::move(rhs.state_.message);
    return *this;
}

}// namespace sled

#endif// SLED_UTILITY_STATUS_H
