// Copyright 2023 Google LLC
//
// 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
//
//      https://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.

// Generated by the Codegen C++ plugin.
// If you make any local changes, they will be lost.
// source: google/cloud/compute/packet_mirrorings/v1/packet_mirrorings.proto

#include "google/cloud/compute/packet_mirrorings/v1/packet_mirrorings_client.h"
#include "google/cloud/compute/packet_mirrorings/v1/packet_mirrorings_connection_idempotency_policy.h"
#include "google/cloud/compute/packet_mirrorings/v1/packet_mirrorings_options.h"
#include "google/cloud/common_options.h"
#include "google/cloud/credentials.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/polling_policy.h"
#include "google/cloud/testing_util/example_driver.h"
#include "google/cloud/universe_domain.h"
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

// clang-format off
// main-dox-marker: compute_packet_mirrorings_v1::PacketMirroringsClient
// lro-marker: true
// clang-format on
namespace {

void SetClientEndpoint(std::vector<std::string> const& argv) {
  if (!argv.empty()) {
    throw google::cloud::testing_util::Usage{"set-client-endpoint"};
  }
  //! [set-client-endpoint]
  // This configuration is common with Private Google Access:
  //     https://cloud.google.com/vpc/docs/private-google-access
  auto options = google::cloud::Options{}.set<google::cloud::EndpointOption>(
      "private.googleapis.com");
  auto vpc_client =
      google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
          google::cloud::compute_packet_mirrorings_v1::
              MakePacketMirroringsConnectionRest(options));
  //! [set-client-endpoint]
}

void SetClientUniverseDomain(std::vector<std::string> const& argv) {
  if (!argv.empty()) {
    throw google::cloud::testing_util::Usage{"set-client-universe-domain"};
  }
  //! [set-client-universe-domain]
  google::cloud::Options options;

  // AddUniverseDomainOption interrogates the UnifiedCredentialsOption, if set,
  // in the provided Options for the Universe Domain associated with the
  // credentials and adds it to the set of Options.
  // If no UnifiedCredentialsOption is set, GoogleDefaultCredentials are used.
  auto ud_options = google::cloud::AddUniverseDomainOption(std::move(options));

  if (!ud_options.ok()) throw std::move(ud_options).status();
  auto ud_client =
      google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
          google::cloud::compute_packet_mirrorings_v1::
              MakePacketMirroringsConnectionRest(*ud_options));
  //! [set-client-universe-domain]
}

//! [custom-idempotency-policy]
class CustomIdempotencyPolicy
    : public google::cloud::compute_packet_mirrorings_v1::
          PacketMirroringsConnectionIdempotencyPolicy {
 public:
  ~CustomIdempotencyPolicy() override = default;
  std::unique_ptr<google::cloud::compute_packet_mirrorings_v1::
                      PacketMirroringsConnectionIdempotencyPolicy>
  clone() const override {
    return std::make_unique<CustomIdempotencyPolicy>(*this);
  }
  // Override inherited functions to define as needed.
};
//! [custom-idempotency-policy]

void SetRetryPolicy(std::vector<std::string> const& argv) {
  if (!argv.empty()) {
    throw google::cloud::testing_util::Usage{"set-client-retry-policy"};
  }
  //! [set-retry-policy]
  auto options =
      google::cloud::Options{}
          .set<google::cloud::compute_packet_mirrorings_v1::
                   PacketMirroringsConnectionIdempotencyPolicyOption>(
              CustomIdempotencyPolicy().clone())
          .set<google::cloud::compute_packet_mirrorings_v1::
                   PacketMirroringsRetryPolicyOption>(
              google::cloud::compute_packet_mirrorings_v1::
                  PacketMirroringsLimitedErrorCountRetryPolicy(3)
                      .clone())
          .set<google::cloud::compute_packet_mirrorings_v1::
                   PacketMirroringsBackoffPolicyOption>(
              google::cloud::ExponentialBackoffPolicy(
                  /*initial_delay=*/std::chrono::milliseconds(200),
                  /*maximum_delay=*/std::chrono::seconds(45),
                  /*scaling=*/2.0)
                  .clone());
  auto connection = google::cloud::compute_packet_mirrorings_v1::
      MakePacketMirroringsConnectionRest(options);

  // c1 and c2 share the same retry policies
  auto c1 = google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
      connection);
  auto c2 = google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
      connection);

  // You can override any of the policies in a new client. This new client
  // will share the policies from c1 (or c2) *except* for the retry policy.
  auto c3 = google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
      connection, google::cloud::Options{}
                      .set<google::cloud::compute_packet_mirrorings_v1::
                               PacketMirroringsRetryPolicyOption>(
                          google::cloud::compute_packet_mirrorings_v1::
                              PacketMirroringsLimitedTimeRetryPolicy(
                                  std::chrono::minutes(5))
                                  .clone()));

  // You can also override the policies in a single call:
  // c3.SomeRpc(..., google::cloud::Options{}
  //     .set<google::cloud::compute_packet_mirrorings_v1::PacketMirroringsRetryPolicyOption>(
  //       google::cloud::compute_packet_mirrorings_v1::PacketMirroringsLimitedErrorCountRetryPolicy(10).clone()));
  //! [set-retry-policy]
}

void SetPollingPolicy(std::vector<std::string> const& argv) {
  if (!argv.empty()) {
    throw google::cloud::testing_util::Usage{"set-client-policy-policy"};
  }
  //! [set-polling-policy]

  // The polling policy controls how the client waits for long-running
  // operations. `GenericPollingPolicy<>` combines existing policies.
  // In this case, keep polling until the operation completes (with success
  // or error) or 45 minutes, whichever happens first. Initially pause for
  // 10 seconds between polling requests, increasing the pause by a factor
  // of 4 until it becomes 2 minutes.
  auto options =
      google::cloud::Options{}
          .set<google::cloud::compute_packet_mirrorings_v1::
                   PacketMirroringsPollingPolicyOption>(
              google::cloud::GenericPollingPolicy<
                  google::cloud::compute_packet_mirrorings_v1::
                      PacketMirroringsRetryPolicyOption::Type,
                  google::cloud::compute_packet_mirrorings_v1::
                      PacketMirroringsBackoffPolicyOption::Type>(
                  google::cloud::compute_packet_mirrorings_v1::
                      PacketMirroringsLimitedTimeRetryPolicy(
                          /*maximum_duration=*/std::chrono::minutes(45))
                          .clone(),
                  google::cloud::ExponentialBackoffPolicy(
                      /*initial_delay=*/std::chrono::seconds(10),
                      /*maximum_delay=*/std::chrono::minutes(2),
                      /*scaling=*/4.0)
                      .clone())
                  .clone());

  auto connection = google::cloud::compute_packet_mirrorings_v1::
      MakePacketMirroringsConnectionRest(options);

  // c1 and c2 share the same polling policies.
  auto c1 = google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
      connection);
  auto c2 = google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
      connection);
  //! [set-polling-policy]
}

void WithServiceAccount(std::vector<std::string> const& argv) {
  if (argv.size() != 1 || argv[0] == "--help") {
    throw google::cloud::testing_util::Usage{"with-service-account <keyfile>"};
  }
  //! [with-service-account]
  [](std::string const& keyfile) {
    auto is = std::ifstream(keyfile);
    is.exceptions(std::ios::badbit);  // Minimal error handling in examples
    auto contents = std::string(std::istreambuf_iterator<char>(is.rdbuf()), {});
    auto options =
        google::cloud::Options{}.set<google::cloud::UnifiedCredentialsOption>(
            google::cloud::MakeServiceAccountCredentials(contents));
    return google::cloud::compute_packet_mirrorings_v1::PacketMirroringsClient(
        google::cloud::compute_packet_mirrorings_v1::
            MakePacketMirroringsConnectionRest(options));
  }
  //! [with-service-account]
  (argv.at(0));
}

void AutoRun(std::vector<std::string> const& argv) {
  namespace examples = ::google::cloud::testing_util;
  using ::google::cloud::internal::GetEnv;
  if (!argv.empty()) throw examples::Usage{"auto"};
  examples::CheckEnvironmentVariablesAreSet(
      {"GOOGLE_CLOUD_CPP_TEST_SERVICE_ACCOUNT_KEYFILE"});
  auto const keyfile =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_SERVICE_ACCOUNT_KEYFILE").value();

  std::cout << "\nRunning SetClientEndpoint() example" << std::endl;
  SetClientEndpoint({});

  std::cout << "\nRunning SetRetryPolicy() example" << std::endl;
  SetRetryPolicy({});

  std::cout << "\nRunning SetPollingPolicy() example" << std::endl;
  SetPollingPolicy({});

  std::cout << "\nRunning WithServiceAccount() example" << std::endl;
  WithServiceAccount({keyfile});

  std::cout << "\nRunning SetClientUniverseDomain() example" << std::endl;
  SetClientUniverseDomain({});
}

}  // namespace

int main(int argc, char* argv[]) {  // NOLINT(bugprone-exception-escape)
  google::cloud::testing_util::Example example({
      {"set-client-endpoint", SetClientEndpoint},
      {"set-retry-policy", SetRetryPolicy},
      {"set-polling-policy", SetPollingPolicy},
      {"with-service-account", WithServiceAccount},
      {"set-client-universe-domain", SetClientUniverseDomain},
      {"auto", AutoRun},
  });
  return example.Run(argc, argv);
}
