#pragma once

#include "frames.h"

#include <balancer/client/experimental/error/error.h>

#include <infra/libs/outcome/result.h>

#include <util/generic/maybe.h>
#include <util/datetime/base.h>

#include <functional>

namespace NHttp {
class IResponseParser;

/// Через интерфейс IRequestContext мы управляем активным запросом.
/// Можно отправить и прочитать следующий блок данных или вовсе отменить запрос.
class IRequestContext {
  public:

    using TReadResult = TExpected<std::any, TError>;
    using TReadHandler = std::function<void(TReadResult)>;

    /// Реализация должна гарантировать, что вызов деструктора аналогичен вызову Cancel.
    virtual ~IRequestContext() = default;

    /// Если запрос активен, то метод Cancel отменяет его. Иначе ничего не делает.
    virtual void Cancel() noexcept = 0;

    /// Метод Write отправляет следующий блок данных. Возможен std::abort, если в запросе не включен Chunked-Encoding.
    /// Пустой фрейм означает конец потока данных.
    /// Последующие вызовы Write не будут иметь эффекта.
    /// \param frame данные для отправки
    virtual void Write(TMaybe<TRequestFrame> frame) noexcept = 0;

    /// Метод Read позволяет последовательно читать фреймы ответа.
    /// Переданный парсер осуществляет проверку и десериализацию фреймов. Так сделано, чтобы
    /// при построении каскада реализаций IRequester можно было прокинуть парсер
    /// до самой нижней реализации. Это, например, важно, если результат
    /// парсинга влияет на возможность перезапроса, когда такая логика реализована в одной
    /// из верхних реализаций IRequester. Ответ возвращается в структуре TParsedFrame, которая содержит,
    /// как сырые http фреймы, так и их десериализованное представление.
    /// Если TMaybe c фреймом пусть, то это означает конец данных. Последующие вызовы тоже будут
    /// возвращать пустой TMaybe.
    /// \param parser реализация парсера
    /// \param deadline максимальное время ожидания ответа.
    /// \param callback будет вызван, когда данные будут получены и пройдут через парсер
    virtual void Read(IResponseParser& parser, TInstant deadline, TReadHandler callback) noexcept = 0;
};
}
