/*
 * Copyright (C) 2026 UBports Foundation.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "RcloneDaemon.h"

#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QObject>
#include <QString>
#include <QUrl>

#include <boost/exception_ptr.hpp>

#include <functional>
#include <memory>
#include <string>
#include <vector>

class QNetworkReply;

// Manage making requests to the rclone daemon
class RcloneClient : public QObject
{
    Q_OBJECT
public:
    using RcCallback = std::function<void(QJsonObject const& result,
                                          boost::exception_ptr const& error)>;

    explicit RcloneClient(QObject* parent = nullptr);
    ~RcloneClient();

    // Post a JSON rc command. item_id used for NotExists error messages.
    void call(QString const& endpoint, QJsonObject const& params, RcCallback cb);
    void call(QString const& endpoint, QJsonObject const& params,
              std::string const& item_id, RcCallback cb);
    void when_ready(RcCallback cb); // Invoke cb once the daemon is ready

    // Build params JSON
    static QJsonObject make_params(std::string const& fs,
                                   std::string const& remote);
    static QJsonObject make_sync_params(std::string const& fs,
                                        std::string const& src_remote,
                                        std::string const& dst_remote,
                                        bool concat_remote = false);

    // URL manipulation helpers
    QUrl base_url() const { return daemon_.base_url(); }
    QNetworkRequest authenticated(QUrl const& url) const;
    QUrl serve_url(std::string const& fs, std::string const& remote_path) const;

    QNetworkAccessManager& network() { return network_; }

private Q_SLOTS:
    void on_daemon_listening();
    void on_daemon_ready();
    void on_daemon_failed(QString const& reason);

private:
    struct PendingCall
    {
        QString endpoint;
        QJsonObject params;
        std::string item_id;
        RcCallback cb;
    };

    void dispatch(PendingCall const& call);
    boost::exception_ptr daemon_failure() const;

    QNetworkAccessManager network_;
    QByteArray auth_header_;
    
    std::vector<PendingCall> pending_calls_;
    RcloneDaemon daemon_;
};
