#include "tool.h"
#include "print.h"

#include <maps/libs/common/include/retry.h>
#include <maps/libs/http/include/request.h>
#include <yandex/maps/proto/firmware_updater/storage/branch.pb.h>

namespace proto = yandex::maps::proto::firmware_updater::storage;

namespace maps::fw_updater::storage::cli {

namespace {

void addDeviceBranch(
    Context& ctx,
    const std::string& hardware,
    const std::string& deviceId,
    const std::string& branch)
{
    http::URL url(ctx.baseUrl());
    url.setPath("/v2/branch/add_device")
        .addParam("hardware", hardware)
        .addParam("deviceid", deviceId)
        .addParam("branch", branch);

    auto response = common::retry([&] {
            http::Request request(ctx.httpClient(), http::POST, url);
            addAuth(request, ctx);
            auto response = request.perform();
            return response;
        },
        ctx.retryPolicy(),
        ctx.responseValidator(),
        ctx.errorReporter());

    REQUIRE(response.status() == 200, errorMessage(response));
    proto::DeviceBranch deviceBranch;
    Y_PROTOBUF_SUPPRESS_NODISCARD deviceBranch.ParseFromString(TString(response.readBody()));
    print(deviceBranch);
}

void removeDeviceBranch(
    Context& ctx,
    const std::string& hardware,
    const std::string& deviceId)
{
    http::URL url(ctx.baseUrl());
    url.setPath("/v2/branch/remove_device")
        .addParam("hardware", hardware)
        .addParam("deviceid", deviceId);

    auto response = common::retry([&] {
            http::Request request(ctx.httpClient(), http::DELETE, url);
            addAuth(request, ctx);
            auto response = request.perform();
            return response;
        },
        ctx.retryPolicy(),
        ctx.responseValidator(),
        ctx.errorReporter());

    REQUIRE(response.status() == 200, errorMessage(response));
}

void listDeviceBranches(
    Context& ctx,
    const std::string& hardware,
    const std::optional<std::string>& deviceId,
    const std::optional<std::string>& branch,
    const std::optional<uint32_t>& results,
    const std::optional<uint32_t>& skip)
{
    http::URL url(ctx.baseUrl());
    url.setPath("/v2/branch/list_devices")
        .addParam("hardware", hardware);

    if (deviceId) {
        url.addParam("deviceid", *deviceId);
    }
    if (branch) {
        url.addParam("branch", *branch);
    }
    if (results) {
        url.addParam("results", *results);
    }
    if (skip) {
        url.addParam("skip", *skip);
    }

    auto response = common::retry([&] {
            http::Request request(ctx.httpClient(), http::GET, url);
            addAuth(request, ctx);
            auto response = request.perform();
            return response;
        },
        ctx.retryPolicy(),
        ctx.responseValidator(),
        ctx.errorReporter());

    REQUIRE(response.responseClass() == http::ResponseClass::Success,
            errorMessage(response));
    proto::DeviceBranchesList deviceBranchesList;
    Y_PROTOBUF_SUPPRESS_NODISCARD deviceBranchesList.ParseFromString(TString(response.readBody()));
    print(deviceBranchesList);
}

} // namespace


void handleDeviceBranchCommand(
    Context& ctx,
    const Options& options)
{
    ASSERT(options.command() == Command::DeviceBranch);

    auto subCommand = options.subCommand<DeviceBranchSubCommand>();

    switch(subCommand) {
        case DeviceBranchSubCommand::Add:
            addDeviceBranch(ctx, options.hardware(), options.deviceId(), options.branch());
            break;
        case DeviceBranchSubCommand::Remove:
            removeDeviceBranch(ctx, options.hardware(), options.deviceId());
            break;
        case DeviceBranchSubCommand::List:
            listDeviceBranches(ctx, options.hardware(),
                               options.deviceId.optional(), options.branch.optional(),
                               options.results.optional(), options.skip.optional());
            break;
    }

}

} // namespace maps::fw_updater::storage::cli
