#include "httpdecoder.h"

#include <util/generic/overloaded.h>

namespace {

enum class EInputType {
    Chunked,
    LengthEqual,
    Unknown
};

EInputType GetInputType(ui16 version, bool chunked, bool haveLength) {
    if (version == 0) {
        if (haveLength) {
            return EInputType::LengthEqual;
        } else if (chunked) {
            return EInputType::Chunked;
        }
    } else {
        if (chunked) {
            return EInputType::Chunked;
        } else if (haveLength) {
            return EInputType::LengthEqual;
        }
    }
    return EInputType::Unknown;
}

}  // namespace

namespace NSrvKernel {

namespace NPrivate {

TError THttpDecoder::Recv(TChunkList& lst, TInstant deadline) noexcept {
    return std::visit(TOverloaded{
        [&](auto& slave) { return slave.Recv(lst, deadline); },
        [](std::monostate) -> TError { Y_FAIL(); },
    }, Impl_);
}

}  // namespace NPrivate

void TFromClientDecoder::Init(const TRequest& request) noexcept {
    const auto& props = request.Props();
    auto inputType = GetInputType(props.Version, props.ChunkedTransfer,
                                  props.ContentLength.has_value());
    if (inputType == EInputType::LengthEqual) {
        Decoder_.InitLengthEqualInput(*props.ContentLength);
    } else if (inputType == EInputType::Chunked) {
        Decoder_.InitChunkedInput();
    } else if (props.HTTP2) {
        Decoder_.InitSlaveInput();
    } else {
        Decoder_.InitNullInput();
    }
}

void TFromBackendDecoder::Init(const TResponse& response) noexcept {
    const auto& props = response.Props();
    auto inputType = GetInputType(props.Version, props.ChunkedTransfer,
                                  props.ContentLength.has_value());
    if (HeadRequest_) {
        Decoder_.InitNullInput();
    } else if (inputType == EInputType::LengthEqual) {
        Decoder_.InitLengthEqualInput(*props.ContentLength);
    } else if (inputType == EInputType::Chunked) {
        Decoder_.InitChunkedInput();
    } else {
        const ui32 status = response.ResponseLine().StatusCode;

        if (NullResponseBody(status)) {
            Decoder_.InitNullInput();
        } else {
            Decoder_.InitSlaveInput();
        }
    }
}


}  // namespace NSrvKernel
