/*
 * Copyright 2024 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_localexecutioninstance.h>
#include <buildboxcasd_requestcontextmanager.h>

#include <buildboxcommon_logging.h>

#include <google/rpc/code.pb.h>
#include <google/rpc/status.pb.h>

#include <memory>
#include <utility>

using namespace buildboxcasd;
using namespace buildboxcommon;

LocalExecutionInstance::LocalExecutionInstance(
    const std::shared_ptr<LocalExecutionScheduler> &scheduler,
    const std::string &instanceName)
    : ExecutionInstance(instanceName), d_scheduler(scheduler),
      d_casInstanceNameForRunner(instanceName)
{
    d_execClient = d_scheduler->createClient(d_casInstanceNameForRunner);
}

LocalExecutionInstance::LocalExecutionInstance(
    const LocalExecutionInstance &other, const std::string &instanceName)
    : ExecutionInstance(instanceName), d_scheduler(other.d_scheduler),
      d_casInstanceNameForRunner(other.d_casInstanceNameForRunner)
{
    /* Don't share LocalExecutionClient with the other instance as `stop()`
     * in this instance must not cancel operations of the other instance.
     */
    d_execClient = d_scheduler->createClient(d_casInstanceNameForRunner);
}

LocalExecutionInstance::~LocalExecutionInstance() { this->stop(); }

std::shared_ptr<ExecutionInstance>
LocalExecutionInstance::clone(const std::string &instanceName)
{
    return std::make_shared<LocalExecutionInstance>(*this, instanceName);
}

grpc::Status
LocalExecutionInstance::Execute(ServerContext *ctx,
                                const ExecuteRequest &request,
                                ServerWriterInterface<Operation> *writer)
{
    if (request.action_digest().hash().empty()) {
        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
                            "Missing action digest");
    }

    std::string operationPrefix = d_instance_name + "#";
    return d_scheduler->Execute(ctx, request, writer, d_execClient,
                                operationPrefix);
}

grpc::Status
LocalExecutionInstance::WaitExecution(ServerContext *ctx,
                                      const WaitExecutionRequest &request,
                                      ServerWriterInterface<Operation> *writer)
{
    return d_scheduler->WaitExecution(ctx, request, writer);
}

grpc::Status
LocalExecutionInstance::GetOperation(const GetOperationRequest &request,
                                     Operation *response)
{
    return d_scheduler->GetOperation(request, response);
}

grpc::Status
LocalExecutionInstance::CancelOperation(const CancelOperationRequest &request,
                                        google::protobuf::Empty *response)
{
    return d_scheduler->CancelOperation(request, response);
}

void LocalExecutionInstance::stop() { d_execClient->cancelAllOperations(); }
