/*
 * 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 <buildboxcasd_localrainstance.h>

#include <buildboxcasd_metricnames.h>

#include <buildboxcommon_exception.h>
#include <buildboxcommon_fileutils.h>
#include <buildboxcommon_logging.h>
#include <buildboxcommon_timeutils.h>
#include <buildboxcommonmetrics_countingmetricutil.h>
#include <buildboxcommonmetrics_countingmetricvalue.h>
#include <buildboxcommonmetrics_durationmetrictimer.h>
#include <buildboxcommonmetrics_metricguard.h>

#include <utility>

using namespace buildboxcasd;
using namespace buildboxcommon;

LocalRaInstance::LocalRaInstance(
    const std::shared_ptr<FsLocalAssetStorage> &asset_storage)
    : RaInstance(), d_assetStorage(asset_storage)
{
}

grpc::Status LocalRaInstance::FetchBlob(const FetchBlobRequest &request,
                                        FetchBlobResponse *response)
{
    buildboxcommon::buildboxcommonmetrics::MetricGuard<
        buildboxcommon::buildboxcommonmetrics::DurationMetricTimer>
        mt(MetricNames::TIMER_NAME_RA_FETCH_BLOB);

    if (request.uris_size() == 0) {
        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
                            "FetchBlob: Missing URI");
    }

    if (d_assetStorage->lookup(request, response)) {
        buildboxcommonmetrics::CountingMetricUtil::recordCounterMetric(
            MetricNames::COUNTER_NAME_RA_FETCH_BLOB_HITS, 1);
        return grpc::Status::OK;
    }
    else {
        buildboxcommonmetrics::CountingMetricUtil::recordCounterMetric(
            MetricNames::COUNTER_NAME_RA_FETCH_BLOB_MISSES, 1);
        return grpc::Status(grpc::StatusCode::NOT_FOUND,
                            "Asset not found in local cache.");
    }
}

grpc::Status
LocalRaInstance::FetchDirectory(const FetchDirectoryRequest &request,
                                FetchDirectoryResponse *response)
{
    buildboxcommon::buildboxcommonmetrics::MetricGuard<
        buildboxcommon::buildboxcommonmetrics::DurationMetricTimer>
        mt(MetricNames::TIMER_NAME_RA_FETCH_DIRECTORY);

    if (request.uris_size() == 0) {
        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
                            "FetchDirectory: Missing URI");
    }

    if (d_assetStorage->lookup(request, response)) {
        buildboxcommonmetrics::CountingMetricUtil::recordCounterMetric(
            MetricNames::COUNTER_NAME_RA_FETCH_DIRECTORY_HITS, 1);
        return grpc::Status::OK;
    }
    else {
        buildboxcommonmetrics::CountingMetricUtil::recordCounterMetric(
            MetricNames::COUNTER_NAME_RA_FETCH_DIRECTORY_MISSES, 1);
        return grpc::Status(grpc::StatusCode::NOT_FOUND,
                            "Asset not found in local cache.");
    }
}

grpc::Status LocalRaInstance::PushBlob(const PushBlobRequest &request,
                                       PushBlobResponse *)
{
    buildboxcommon::buildboxcommonmetrics::MetricGuard<
        buildboxcommon::buildboxcommonmetrics::DurationMetricTimer>
        mt(MetricNames::TIMER_NAME_RA_PUSH_BLOB);

    if (request.uris_size() == 0) {
        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
                            "PushBlob: Missing URI");
    }

    d_assetStorage->insert(request);

    return grpc::Status::OK;
}

grpc::Status
LocalRaInstance::PushDirectory(const PushDirectoryRequest &request,
                               PushDirectoryResponse *)
{
    buildboxcommon::buildboxcommonmetrics::MetricGuard<
        buildboxcommon::buildboxcommonmetrics::DurationMetricTimer>
        mt(MetricNames::TIMER_NAME_RA_PUSH_DIRECTORY);

    if (request.uris_size() == 0) {
        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
                            "PushDirectory: Missing URI");
    }

    d_assetStorage->insert(request);

    return grpc::Status::OK;
}
