#ifndef _TILE_NET_HTTP_HTTP_MESSAGE_H
#define _TILE_NET_HTTP_HTTP_MESSAGE_H

#pragma once
#include "tile/base/buffer.h"
#include "tile/net/http/http_headers.h"
#include "tile/net/http/types.h"

namespace tile {
namespace http {
class HttpMessage {
public:
    HttpVersion version() const noexcept { return version_; }

    void set_version(HttpVersion v) noexcept { version_ = v; }

    HttpHeaders *headers() noexcept { return &headers_; }

    const HttpHeaders *headers() const noexcept { return &headers_; }

    std::string *body() noexcept { return body_str_ ? &*body_str_ : StringifyBody(); }

    const std::string *body() const noexcept { return TILE_LIKELY(body_str_) ? &*body_str_ : StringifyBody(); }

    void set_body(std::string s)
    {
        body_     = std::nullopt;
        body_str_ = std::move(s);
    }

    void set_body(NoncontiguousBuffer &&nb) noexcept
    {
        body_str_ = std::nullopt;
        body_     = std::move(nb);
    }

    std::size_t body_size() const noexcept
    {
        if (TILE_LIKELY(body_str_)) {
            return body_str_->size();
        } else if (TILE_LIKELY(body_)) {
            return body_->ByteSize();
        } else {
            return 0;
        }
    }

    NoncontiguousBuffer *noncontiguous_body() noexcept { return body_ ? &*body_ : nullptr; }

    const NoncontiguousBuffer *noncontiguous_body() const noexcept
    {
        return const_cast<HttpMessage *>(this)->noncontiguous_body();
    }

    void clear() noexcept
    {
        headers_.clear();
        body_str_ = std::nullopt;
        body_     = std::nullopt;
    }

private:
    std::string *StringifyBody() const;

private:
    HttpVersion version_{HttpVersion::Unspecified};
    HttpHeaders headers_;

    mutable std::optional<std::string> body_str_;
    std::optional<NoncontiguousBuffer> body_;
};
}// namespace http
}// namespace tile

#endif// _TILE_NET_HTTP_HTTP_MESSAGE_H
