// Copyright 2021 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.

#include "generator/internal/options_generator.h"
#include "generator/internal/codegen_utils.h"
#include "generator/internal/descriptor_utils.h"
#include "generator/internal/predicate_utils.h"
#include "generator/internal/printer.h"
#include <google/protobuf/descriptor.h>

namespace google {
namespace cloud {
namespace generator_internal {

OptionsGenerator::OptionsGenerator(
    google::protobuf::ServiceDescriptor const* service_descriptor,
    VarsDictionary service_vars,
    std::map<std::string, VarsDictionary> service_method_vars,
    google::protobuf::compiler::GeneratorContext* context,
    std::vector<MixinMethod> const& mixin_methods)
    : ServiceCodeGenerator(
          "options_header_path", service_descriptor, std::move(service_vars),
          std::move(service_method_vars), context, mixin_methods) {}

Status OptionsGenerator::GenerateHeader() {
  HeaderPrint(CopyrightLicenseFileHeader());
  HeaderPrint(  // clang-format off
    "\n"
    "// Generated by the Codegen C++ plugin.\n"
    "// If you make any local changes, they will be lost.\n"
    "// source: $proto_file_name$\n"
    "\n"
    "#ifndef $header_include_guard$\n"
    "#define $header_include_guard$\n");
  // clang-format on

  // includes
  HeaderPrint("\n");
  HeaderLocalIncludes({vars("connection_header_path"),
                       vars("idempotency_policy_header_path"),
                       "google/cloud/backoff_policy.h",
                       "google/cloud/options.h", "google/cloud/version.h"});
  HeaderSystemIncludes({"memory"});

  auto result = HeaderOpenNamespaces();
  if (!result.ok()) return result;

  HeaderPrint(
      R"""(
/**
 * Use with `google::cloud::Options` to configure the retry policy.
 *
 * @ingroup $product_options_page$
 */
struct $retry_policy_name$Option {
  using Type = std::shared_ptr<$retry_policy_name$>;
};

/**
 * Use with `google::cloud::Options` to configure the backoff policy.
 *
 * @ingroup $product_options_page$
 */
struct $service_name$BackoffPolicyOption {
  using Type = std::shared_ptr<BackoffPolicy>;
};

/**
 * Use with `google::cloud::Options` to configure which operations are retried.
 *
 * @ingroup $product_options_page$
 */
struct $idempotency_class_name$Option {
  using Type = std::shared_ptr<$idempotency_class_name$>;
};
)""");

  if (HasLongrunningMethod()) {
    HeaderPrint(R"""(
/**
 * Use with `google::cloud::Options` to configure the long-running operations
 * polling policy.
 *
 * @ingroup $product_options_page$
 */
struct $service_name$PollingPolicyOption {
  using Type = std::shared_ptr<PollingPolicy>;
};

/**
 * The options applicable to $service_name$.
 *
 * @ingroup $product_options_page$
 */
using $service_name$PolicyOptionList =
    OptionList<$service_name$RetryPolicyOption,
               $service_name$BackoffPolicyOption,
               $service_name$PollingPolicyOption,
               $idempotency_class_name$Option>;
)""");
  } else {
    HeaderPrint(R"""(
/**
 * The options applicable to $service_name$.
 *
 * @ingroup $product_options_page$
 */
using $service_name$PolicyOptionList =
    OptionList<$service_name$RetryPolicyOption,
               $service_name$BackoffPolicyOption,
               $idempotency_class_name$Option>;
)""");
  }

  HeaderCloseNamespaces();
  // close header guard
  HeaderPrint("\n#endif  // $header_include_guard$\n");
  return {};
}

Status OptionsGenerator::GenerateCc() { return {}; }

}  // namespace generator_internal
}  // namespace cloud
}  // namespace google
