// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
#pragma once

extern "C"
{
#include <nghttp2/nghttp2.h>
}

#include "logging.hpp"

#include <bit>
#include <span>
#include <string_view>

/* This file contains RAII compatible adapters for nghttp2 structures.  They
 * attempt to be as close to a direct call as possible, while keeping the RAII
 * lifetime safety for the various classes.  Because of this, they use the same
 * naming as nghttp2, so ignore naming violations.
 */

// NOLINTBEGIN(readability-identifier-naming,
// readability-make-member-function-const)

struct nghttp2_session;

struct nghttp2_session_callbacks
{
    friend nghttp2_session;
    nghttp2_session_callbacks()
    {
        nghttp2_session_callbacks_new(&ptr);
    }

    ~nghttp2_session_callbacks()
    {
        nghttp2_session_callbacks_del(ptr);
    }

    nghttp2_session_callbacks(const nghttp2_session_callbacks&) = delete;
    nghttp2_session_callbacks& operator=(const nghttp2_session_callbacks&) =
        delete;
    nghttp2_session_callbacks(nghttp2_session_callbacks&&) = delete;
    nghttp2_session_callbacks& operator=(nghttp2_session_callbacks&&) = delete;

    void setSendCallback(nghttp2_send_callback sendCallback)
    {
        nghttp2_session_callbacks_set_send_callback(ptr, sendCallback);
    }

    void setOnFrameRecvCallback(nghttp2_on_frame_recv_callback recvCallback)
    {
        nghttp2_session_callbacks_set_on_frame_recv_callback(ptr, recvCallback);
    }

    void setOnStreamCloseCallback(nghttp2_on_stream_close_callback onClose)
    {
        nghttp2_session_callbacks_set_on_stream_close_callback(ptr, onClose);
    }

    void setOnHeaderCallback(nghttp2_on_header_callback onHeader)
    {
        nghttp2_session_callbacks_set_on_header_callback(ptr, onHeader);
    }

    void setOnBeginHeadersCallback(
        nghttp2_on_begin_headers_callback onBeginHeaders)
    {
        nghttp2_session_callbacks_set_on_begin_headers_callback(
            ptr, onBeginHeaders);
    }

    void setSendDataCallback(nghttp2_send_data_callback onSendData)
    {
        nghttp2_session_callbacks_set_send_data_callback(ptr, onSendData);
    }
    void setBeforeFrameSendCallback(
        nghttp2_before_frame_send_callback beforeSendFrame)
    {
        nghttp2_session_callbacks_set_before_frame_send_callback(
            ptr, beforeSendFrame);
    }
    void setAfterFrameSendCallback(
        nghttp2_on_frame_send_callback afterSendFrame)
    {
        nghttp2_session_callbacks_set_on_frame_send_callback(ptr,
                                                             afterSendFrame);
    }
    void setAfterFrameNoSendCallback(
        nghttp2_on_frame_not_send_callback afterSendFrame)
    {
        nghttp2_session_callbacks_set_on_frame_not_send_callback(
            ptr, afterSendFrame);
    }

    void setOnDataChunkRecvCallback(
        nghttp2_on_data_chunk_recv_callback afterDataChunkRecv)
    {
        nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
            ptr, afterDataChunkRecv);
    }

  private:
    nghttp2_session_callbacks* get()
    {
        return ptr;
    }

    nghttp2_session_callbacks* ptr = nullptr;
};

struct nghttp2_session
{
    explicit nghttp2_session(nghttp2_session_callbacks& callbacks)
    {
        if (nghttp2_session_server_new(&ptr, callbacks.get(), nullptr) != 0)
        {
            BMCWEB_LOG_ERROR("nghttp2_session_server_new failed");
            return;
        }
    }

    ~nghttp2_session()
    {
        nghttp2_session_del(ptr);
    }

    // explicitly uncopyable
    nghttp2_session(const nghttp2_session&) = delete;
    nghttp2_session& operator=(const nghttp2_session&) = delete;

    nghttp2_session(nghttp2_session&& other) noexcept : ptr(other.ptr)
    {
        other.ptr = nullptr;
    }

    nghttp2_session& operator=(nghttp2_session&& other) noexcept = delete;

    int submitSettings(std::span<nghttp2_settings_entry> iv)
    {
        return nghttp2_submit_settings(ptr, NGHTTP2_FLAG_NONE, iv.data(),
                                       iv.size());
    }

    int sessionUpgrade2(std::string_view settingsPayload, bool headRequest)
    {
        return nghttp2_session_upgrade2(
            ptr, std::bit_cast<uint8_t*>(settingsPayload.data()),
            settingsPayload.size(), headRequest ? 1 : 0, nullptr);
    }

    void setUserData(void* object)
    {
        nghttp2_session_set_user_data(ptr, object);
    }

    ssize_t memRecv(std::span<const uint8_t> buffer)
    {
        return nghttp2_session_mem_recv(ptr, buffer.data(), buffer.size());
    }

    std::span<const uint8_t> memSend()
    {
        const uint8_t* bytes = nullptr;
        ssize_t size = nghttp2_session_mem_send(ptr, &bytes);
        return {bytes, static_cast<size_t>(size)};
    }

    int submitResponse(int32_t streamId, std::span<const nghttp2_nv> headers,
                       const nghttp2_data_provider* dataPrd)
    {
        return nghttp2_submit_response(ptr, streamId, headers.data(),
                                       headers.size(), dataPrd);
    }

  private:
    nghttp2_session* ptr = nullptr;
};

struct nghttp2_hd_inflater_ex
{
    nghttp2_hd_inflater* ptr = nullptr;

  public:
    nghttp2_hd_inflater_ex()
    {
        if (nghttp2_hd_inflate_new(&ptr) != 0)
        {
            BMCWEB_LOG_ERROR("nghttp2_hd_inflater_new failed");
        }
    }

    ssize_t hd2(nghttp2_nv* nvOut, int* inflateFlags, const uint8_t* in,
                size_t inlen, int inFinal)
    {
        return nghttp2_hd_inflate_hd2(ptr, nvOut, inflateFlags, in, inlen,
                                      inFinal);
    }

    int endHeaders()
    {
        return nghttp2_hd_inflate_end_headers(ptr);
    }

    nghttp2_hd_inflater_ex(const nghttp2_hd_inflater_ex&) = delete;
    nghttp2_hd_inflater_ex& operator=(const nghttp2_hd_inflater_ex&) = delete;
    nghttp2_hd_inflater_ex& operator=(nghttp2_hd_inflater_ex&&) = delete;
    nghttp2_hd_inflater_ex(nghttp2_hd_inflater_ex&& other) = delete;

    ~nghttp2_hd_inflater_ex()
    {
        if (ptr != nullptr)
        {
            nghttp2_hd_inflate_del(ptr);
        }
    }
};
// NOLINTEND(readability-identifier-naming,
// readability-make-member-function-const)
