/*
 * Copyright 2019 Bloomberg Finance 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_requestmetadata.h>

#include <buildboxcommon_protos.h>

using namespace buildboxcommon;

const std::string RequestMetadataGenerator::HEADER_NAME =
    "build.bazel.remote.execution.v2.requestmetadata-bin";

RequestMetadataGenerator::RequestMetadataGenerator() {}

RequestMetadataGenerator::RequestMetadataGenerator(
    const std::string &tool_name, const std::string &tool_version)

{
    this->set_tool_details(tool_name, tool_version);
}

void RequestMetadataGenerator::attach_request_metadata(
    grpc::ClientContext *context) const
{
    this->attach_request_metadata(context, d_action_id, d_tool_invocation_id,
                                  d_correlated_invocations_id,
                                  d_actionMnemonic, d_targetId,
                                  d_configurationId);
}

void RequestMetadataGenerator::set_tool_details(
    const std::string &tool_name, const std::string &tool_version)
{
    d_tool_details.set_tool_name(tool_name);
    d_tool_details.set_tool_version(tool_version);
}

void RequestMetadataGenerator::set_action_id(const std::string &action_id)
{
    d_action_id = action_id;
}

void RequestMetadataGenerator::set_tool_invocation_id(
    const std::string &tool_invocation_id)
{
    d_tool_invocation_id = tool_invocation_id;
}

void RequestMetadataGenerator::set_correlated_invocations_id(
    const std::string &correlated_invocations_id)
{
    d_correlated_invocations_id = correlated_invocations_id;
}

void RequestMetadataGenerator::set_action_mnemonic(
    const std::string &actionMnemonic)
{
    d_actionMnemonic = actionMnemonic;
}

void RequestMetadataGenerator::set_target_id(const std::string &targetId)
{
    d_targetId = targetId;
}

void RequestMetadataGenerator::set_configuration_id(
    const std::string &configurationId)
{
    d_configurationId = configurationId;
}

const std::string &RequestMetadataGenerator::getActionId() const
{
    return d_action_id;
}
const std::string &RequestMetadataGenerator::getToolInvocationId() const
{
    return d_tool_invocation_id;
}
const std::string &RequestMetadataGenerator::getCorrelatedInvocationsId() const
{
    return d_correlated_invocations_id;
}
const std::string &RequestMetadataGenerator::getActionMnemonic() const
{
    return d_actionMnemonic;
}
const std::string &RequestMetadataGenerator::getTargetId() const
{
    return d_targetId;
}
const std::string &RequestMetadataGenerator::getConfigurationId() const
{
    return d_configurationId;
}
const ToolDetails &RequestMetadataGenerator::getToolDetails() const
{
    return d_tool_details;
}

RequestMetadata
buildboxcommon::RequestMetadataGenerator::parse_request_metadata(
    const std::multimap<grpc::string_ref, grpc::string_ref> &metadataMap)
{
    RequestMetadata metadataProto;
    auto itr = metadataMap.find(HEADER_NAME);
    if (itr != metadataMap.end()) {
        std::string metadataString((itr->second).begin(), (itr->second).end());
        if (!metadataProto.ParseFromString(metadataString)) {
            BUILDBOXCOMMON_THROW_EXCEPTION(
                std::invalid_argument,
                "Unable to parse found RequestMetadata");
        }
    }
    return metadataProto;
}

RequestMetadata RequestMetadataGenerator::generate_request_metadata(
    const std::string &actionId, const std::string &toolInvocationId,
    const std::string &correlatedInvocationsId,
    const std::string &actionMnemonic, const std::string &targetId,
    const std::string &configurationId) const
{
    RequestMetadata metadata;
    metadata.mutable_tool_details()->CopyFrom(d_tool_details);

    metadata.set_action_id(actionId);
    metadata.set_tool_invocation_id(toolInvocationId);
    metadata.set_correlated_invocations_id(correlatedInvocationsId);
    metadata.set_action_mnemonic(actionMnemonic);
    metadata.set_target_id(targetId);
    metadata.set_configuration_id(configurationId);

    return metadata;
}

void RequestMetadataGenerator::attach_request_metadata(
    grpc::ClientContext *context, const std::string &actionId,
    const std::string &toolInvocationId,
    const std::string &correlatedInvocationsId,
    const std::string &actionMnemonic, const std::string &targetId,
    const std::string &configurationId) const
{
    const RequestMetadata metadata = this->generate_request_metadata(
        actionId, toolInvocationId, correlatedInvocationsId, actionMnemonic,
        targetId, configurationId);

    context->AddMetadata(HEADER_NAME, metadata.SerializeAsString());
}
