/*
 * SPDX-FileCopyrightText: 2026 Oak Ridge National Laboratory and Contributors
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ADIOS2_XROOTDHTTPREMOTE_H
#define ADIOS2_XROOTDHTTPREMOTE_H

#include "Remote.h"
#include "adios2/common/ADIOSConfig.h"
#include "adios2/common/ADIOSTypes.h"
#include "adios2/toolkit/profiling/iochrono/IOChrono.h"

#include <atomic>
#include <condition_variable>
#include <deque>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

// Forward declarations for CURL handles
typedef void CURL;
typedef void CURLM;
struct curl_slist;

namespace adios2
{

class XrootdHttpRemote;

/**
 * @brief Async operation state for a single HTTP GET/POST request.
 */
struct AsyncGet
{
    std::promise<bool> promise;
    std::string errorMsg;
    void *destBuffer = nullptr;
    size_t destSize = 0;
    std::vector<char> responseData;
    CURL *easyHandle = nullptr;
    ::curl_slist *headers = nullptr;
};

/**
 * @brief A fully-configured easy handle waiting to be added to the multi handle.
 */
struct PendingSubmit
{
    CURL *easyHandle;
    AsyncGet *asyncOp;
};

/**
 * @brief Shared CURL multi pool singleton.
 *
 * All XrootdHttpRemote instances submit fully-configured easy handles to
 * this pool. A single worker thread drives all transfers via one curl_multi
 * handle, bounding the total number of concurrent TCP connections.
 */
class CurlMultiPool
{
public:
    static CurlMultiPool &getInstance();

    /** Submit a fully-configured easy handle for async execution. Thread-safe. */
    void Submit(CURL *easyHandle, AsyncGet *asyncOp);

    // Non-copyable, non-movable
    CurlMultiPool(const CurlMultiPool &) = delete;
    CurlMultiPool &operator=(const CurlMultiPool &) = delete;

private:
    CurlMultiPool();
    ~CurlMultiPool();

    void WorkerLoop();
    void ProcessCompletedTransfers();

    CURLM *m_MultiHandle = nullptr;
    std::thread m_WorkerThread;
    std::atomic<bool> m_Running{false};
    std::mutex m_QueueMutex;
    std::condition_variable m_QueueCV;
    std::deque<PendingSubmit> m_PendingQueue;
};

/**
 * @brief HTTP/HTTPS-based remote access to ADIOS data via XRootD HTTP-SSI bridge
 *
 * All instances share a single CurlMultiPool for efficient connection pooling.
 */
class XrootdHttpRemote : public Remote
{
public:
    profiling::IOChrono m_Profiler;

    XrootdHttpRemote(const adios2::HostOptions &hostOptions);
    ~XrootdHttpRemote();

    explicit operator bool() const override { return m_OpenSuccess; }

    void Open(const std::string hostname, const int32_t port, const std::string filename,
              const Mode mode, bool RowMajorOrdering, const Params &params = Params()) override;

    GetHandle Get(const char *VarName, size_t Step, size_t StepCount, size_t BlockID, Dims &Count,
                  Dims &Start, Accuracy &accuracy, void *dest) override;

    bool WaitForGet(GetHandle handle) override;
    GetHandle Read(size_t Start, size_t Size, void *Dest) override;

    bool BatchGet(const std::vector<BatchGetRequest> &requests) override;

    void Close() override;

    void SetUseHttps(bool useHttps) { m_UseHttps = useHttps; }
    bool GetUseHttps() const { return m_UseHttps; }
    void SetConnectTimeout(long seconds) { m_ConnectTimeout = seconds; }
    void SetRequestTimeout(long seconds) { m_RequestTimeout = seconds; }
    void SetCACertPath(const std::string &path) { m_CACertPath = path; }
    void SetVerifySSL(bool verify) { m_VerifySSL = verify; }

private:
    std::string BuildRequestString(const char *VarName, size_t Step, size_t StepCount,
                                   size_t BlockID, const Dims &Count, const Dims &Start,
                                   const Accuracy &accuracy);
    std::string BuildBatchRequestString(const std::vector<BatchGetRequest> &requests);
    std::string UrlEncode(const std::string &str);
    CURL *CreateEasyHandle(AsyncGet *asyncOp, const std::string &url, const std::string &postData);

    std::string m_BaseUrl;
    std::string m_Filename;
    std::string m_EngineParams;
    Mode m_Mode;
    bool m_RowMajorOrdering;
    bool m_OpenSuccess = false;

    bool m_UseHttps = true;
    long m_ConnectTimeout = 30;
    long m_RequestTimeout = 300;
    std::string m_CACertPath;
    bool m_VerifySSL = true;
};

} // end namespace adios2

#endif // ADIOS2_XROOTDHTTPREMOTE_H
