#include "httpencoder.h"

#include <util/generic/overloaded.h>

namespace NSrvKernel {

namespace NPrivate {

void TreatConnectionV0(const bool needKeepAlive, const bool explicitConnectionHeader, NSrvKernel::THeaders& headers) {
    if (needKeepAlive) {
        headers.Add("Connection", "Keep-Alive");
    } else if (explicitConnectionHeader) {
        headers.Add("Connection", "Close");
    }
}

void TreatConnectionV1(const bool upgradeRequested, const bool needKeepAlive, const bool explicitConnectionHeader,
                       NSrvKernel::THeaders& headers) {
    if (upgradeRequested) {
        headers.Add("Connection", "Upgrade");
    } else if (!needKeepAlive) {
        headers.Add("Connection", "Close");
    } else if (explicitConnectionHeader) {
        headers.Add("Connection", "Keep-Alive");
    }
}


TError THttpEncoder::Send(TChunkList lst, TInstant deadline) noexcept {
    return std::visit(TOverloaded{
        [&](auto& slave) {
            const bool finished = lst.Empty();
            auto error = slave.Send(std::move(lst), deadline);
            if (finished) {
                Finish();
            }
            return error;
        },
        [&](TFinishedTag&) {
            Y_FAIL("Trying to send after finish");
            return TError{};
        }}, Impl_);
}


}  // namespace NPrivate

TError TToBackendEncoder::DoEncode(THeaders& headers, const TBaseProperties& props, const bool needKeepAlive) noexcept {
    const bool chunkedTransfer = props.ChunkedTransfer;
    const auto version = props.Version;
    const bool isHTTP2 = props.HTTP2;
    const auto contentLength = props.ContentLength;
    const auto upgradeRequested = props.UpgradeRequested;
    const auto explicitConnectionHeader = props.AddExplicitConnectionHeader;

    if (version == 0) {
        if (contentLength) {
            Encoder_.InitContentLength(headers, *contentLength);
        } else {
            Encoder_.InitNullContent();
        }

        NPrivate::TreatConnectionV0(needKeepAlive, explicitConnectionHeader, headers);
    } else if (version == 1) {
        if (chunkedTransfer) {
            Encoder_.InitChunkedTransfer(headers);
        } else if (contentLength) {
            Encoder_.InitContentLength(headers, *contentLength);
        } else {
            if (isHTTP2) {
                Encoder_.InitChunkedTransfer(headers);
            } else {
                Encoder_.InitNullContent();
            }
        }

        NPrivate::TreatConnectionV1(upgradeRequested, needKeepAlive, explicitConnectionHeader, headers);
    } else {
        return Y_MAKE_ERROR(THttpError{505});
    }

    return {};
}

}  // namespace NSrvKernel
