/*
 * Copyright 2024 Bloomberg LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <buildboxcommon_connectionoptions_toml.h>
#include <buildboxcommon_stringutils.h>
#include <buildboxcommon_tomlutils.h>
#include <iostream>

namespace buildboxcommon {

ConnectionOptions
ConnectionOptionsTOML::configureChannel(const toml::table &tomlConfig)
{
    ConnectionOptions co;
    co.reset();
    updateChannel(tomlConfig, co);
    return co;
}

void ConnectionOptionsTOML::updateChannel(const toml::table &tomlConfig,
                                          ConnectionOptions &channel)
{
    AccessPath path;

    if (const auto remote = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "remote", path)) {
        channel.d_url = remote.value();
    }
    if (const auto instance = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "instance", path)) {
        channel.d_instanceName = instance.value();
    }
    if (const auto serverCert = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "server-cert",
            path)) {
        channel.d_serverCertPath = serverCert.value();
    }
    if (const auto clientKey = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "client-key",
            path)) {
        channel.d_clientKeyPath = clientKey.value();
    }
    if (const auto clientCert = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "client-cert",
            path)) {
        channel.d_clientCertPath = clientCert.value();
    }
    if (const auto accessToken = TOMLUtils::readOptionalFromTable<std::string>(
            TOMLUtils::readValue<std::string>, tomlConfig, "access-token",
            path)) {
        channel.d_accessTokenPath = accessToken.value();
    }
    if (const auto tokenReloadInterval =
            TOMLUtils::readOptionalFromTable<int64_t>(
                TOMLUtils::readValue<int64_t>, tomlConfig,
                "token-reload-interval", path)) {
        channel.d_tokenReloadInterval =
            std::to_string(tokenReloadInterval.value());
    }
    if (const auto useGoogleapiAuth = TOMLUtils::readOptionalFromTable<bool>(
            TOMLUtils::readValue<bool>, tomlConfig, "googleapi-auth", path)) {
        channel.d_useGoogleApiAuth = useGoogleapiAuth.value();
    }
    if (const auto &credentialHelper =
            TOMLUtils::readOptionalFromTable<std::string>(
                TOMLUtils::readValue<std::string>, tomlConfig,
                "credential-helper", path)) {
        channel.d_credentialHelperPath = credentialHelper.value();
    }

    // Some options are parsed as strings for backward compatibility
    if (const auto retryLimit = TOMLUtils::readOptionalFromTable<int64_t>(
            TOMLUtils::readValue<int64_t>, tomlConfig, "retry-limit", path)) {
        channel.d_retryLimit = std::to_string(retryLimit.value());
    }
    if (const auto retryDelay = TOMLUtils::readOptionalFromTable<int64_t>(
            TOMLUtils::readValue<int64_t>, tomlConfig, "retry-delay", path)) {
        channel.d_retryDelay = std::to_string(retryDelay.value());
    }
    if (const auto retryOnCodes =
            TOMLUtils::readOptionalFromTable<std::vector<std::string>>(
                std::bind(TOMLUtils::readFromArray<std::string>,
                          TOMLUtils::readValue<std::string>,
                          std::placeholders::_1, std::placeholders::_2),
                tomlConfig, "retry-on-code", path)

    ) {
        channel.d_retryOnCodes.clear();
        for (const auto &code : retryOnCodes.value()) {
            channel.d_retryOnCodes.emplace(
                buildboxcommon::StringUtils::parseStatusCode(code));
        }
    }
    if (const auto requestTimeout = TOMLUtils::readOptionalFromTable<int64_t>(
            TOMLUtils::readValue<int64_t>, tomlConfig, "request-timeout",
            path)) {
        channel.d_requestTimeout = std::to_string(requestTimeout.value());
    }
    if (const auto minThroughput =
            TOMLUtils::readOptionalFromTable<std::string>(
                TOMLUtils::readValue<std::string>, tomlConfig,
                "min-throughput", path)) {
        channel.setMinThroughput(minThroughput.value());
    }

    if (const auto keepaliveTime = TOMLUtils::readOptionalFromTable<int64_t>(
            TOMLUtils::readValue<int64_t>, tomlConfig, "keepalive-time",
            path)) {
        channel.d_keepaliveTime = std::to_string(keepaliveTime.value());
    }
    if (const auto loadBalancingPolicy =
            TOMLUtils::readOptionalFromTable<std::string>(
                TOMLUtils::readValue<std::string>, tomlConfig,
                "load-balancing-policy", path)) {
        channel.d_loadBalancingPolicy = loadBalancingPolicy.value();
    }
}

} // namespace buildboxcommon
