/*
 * Copyright 2020 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 <buildboxworker_actionutils.h>
#include <buildboxworker_metricnames.h>

#include <buildboxcommon_casclient.h>
#include <buildboxcommon_digestgenerator.h>
#include <buildboxcommon_exception.h>
#include <buildboxcommon_logging.h>
#include <buildboxcommon_protos.h>
#include <buildboxcommon_systemutils.h>

#include <buildboxcommonmetrics_durationmetrictimer.h>
#include <buildboxcommonmetrics_metricguard.h>

#include <fcntl.h>
#include <fstream>
#include <unistd.h>
#include <utility>

namespace buildboxworker {

std::pair<buildboxcommon::Action, buildboxcommon::Digest>
ActionUtils::getActionFromLease(
    const proto::Lease &lease,
    const std::shared_ptr<buildboxcommon::CASClient> &casClient)
{

    buildboxcommon::buildboxcommonmetrics::MetricGuard<
        buildboxcommon::buildboxcommonmetrics::DurationMetricTimer>
        mt(MetricNames::TIMER_NAME_DOWNLOAD_ACTION);

    if (lease.payload().Is<buildboxcommon::Action>()) {
        buildboxcommon::Action action;
        lease.payload().UnpackTo(&action);

        const buildboxcommon::Digest digest =
            buildboxcommon::DigestGenerator::hash(action);

        return std::make_pair(action, digest);
    }

    if (lease.payload().Is<buildboxcommon::Digest>()) {
        BUILDBOX_LOG_DEBUG("Payload is of type `Digest`, "
                           "fetching the corresponding "
                           "`Action` from CAS server");

        buildboxcommon::Digest digest;
        lease.payload().UnpackTo(&digest);

        const buildboxcommon::Action action =
            downloadAction(digest, casClient);

        return std::make_pair(action, digest);
    }

    BUILDBOXCOMMON_THROW_EXCEPTION(
        std::runtime_error, "Lease contains unexpected payload type: `"
                                << lease.payload().GetTypeName()
                                << "` . (Expected `Action` or `Digest`.)");
}

buildboxcommon::Action ActionUtils::downloadAction(
    const buildboxcommon::Digest &digest,
    const std::shared_ptr<buildboxcommon::CASClient> &casClient)
{
    try {
        return casClient->fetchMessage<buildboxcommon::Action>(digest);
    }
    catch (const std::exception &e) {
        BUILDBOX_LOG_DEBUG(
            "Failed to fetch digest from CAS server: " << e.what());
        throw;
    }
}

} // namespace buildboxworker
