// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) TypeSpec Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

#include "key_vault_client.hpp"

#include "../private/package_version.hpp"

#include <azure/core/base64.hpp>
#include <azure/core/exception.hpp>
#include <azure/core/http/http.hpp>
#include <azure/core/http/http_status_code.hpp>
#include <azure/core/http/policies/policy.hpp>
#include <azure/core/internal/json/json.hpp>
#include <azure/core/io/body_stream.hpp>

// codegen: insert after includes
#include "azure/keyvault/shared/keyvault_challenge_based_auth.hpp"
#include "azure/keyvault/shared/keyvault_shared.hpp"

using Azure::Security::KeyVault::_internal::KeyVaultChallengeBasedAuthenticationPolicy;
using Azure::Security::KeyVault::_internal::UrlScope;
// codegen: end insert after includes

using namespace Azure::Security::KeyVault::Secrets::_detail;

// codegen: replace KeyVaultClient::KeyVaultClient
KeyVaultClient::KeyVaultClient(
    const std::string& url,
    const std::shared_ptr<const Core::Credentials::TokenCredential>& credential,
    const KeyVaultClientOptions& options)
    : m_url(url), m_apiVersion(options.ApiVersion)
{
  std::vector<std::unique_ptr<Core::Http::Policies::HttpPolicy>> perRetryPolicies;
  std::vector<std::unique_ptr<Core::Http::Policies::HttpPolicy>> perCallPolicies;

  {
    Core::Credentials::TokenRequestContext tokenRequestContext;
    tokenRequestContext.Scopes = {"https://vault.azure.net/.default"};
    perRetryPolicies.emplace_back(std::make_unique<KeyVaultChallengeBasedAuthenticationPolicy>(
        credential, tokenRequestContext));
  }

  m_pipeline = std::make_shared<Core::Http::_internal::HttpPipeline>(
      options,
      "security-keyvault-secrets",
      _detail::PackageVersion::ToString(),
      std::move(perRetryPolicies),
      std::move(perCallPolicies));
}
// codegen: end replace KeyVaultClient::KeyVaultClient

std::string KeyVaultClient::GetUrl() const { return m_url.GetAbsoluteUrl(); }

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::SecretBundle>
KeyVaultClient::SetSecret(
    const std::string& secretName,
    const Models::SecretSetParameters& parameters,
    const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  std::string jsonBody;
  {
    auto jsonRoot = Core::Json::_internal::json::object();
    jsonRoot["value"] = parameters.Value;
    if (parameters.Tags.HasValue())
    {
      jsonRoot["tags"] = Core::Json::_internal::json::object();

      for (auto const& kv : parameters.Tags.Value())
      {
        jsonRoot["tags"][kv.first] = kv.second;
      }
    }

    if (parameters.ContentType.HasValue())
    {
      jsonRoot["contentType"] = parameters.ContentType.Value();
    }

    if (parameters.SecretAttributes.HasValue())
    {
      if (parameters.SecretAttributes.Value().Enabled.HasValue())
      {
        jsonRoot["attributes"]["enabled"] = parameters.SecretAttributes.Value().Enabled.Value();
      }

      if (parameters.SecretAttributes.Value().NotBefore.HasValue())
      {
        jsonRoot["attributes"]["nbf"] = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
            parameters.SecretAttributes.Value().NotBefore.Value());
      }

      if (parameters.SecretAttributes.Value().Expires.HasValue())
      {
        jsonRoot["attributes"]["exp"] = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
            parameters.SecretAttributes.Value().Expires.Value());
      }

      if (parameters.SecretAttributes.Value().Created.HasValue())
      {
        jsonRoot["attributes"]["created"]
            = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
                parameters.SecretAttributes.Value().Created.Value());
      }

      if (parameters.SecretAttributes.Value().Updated.HasValue())
      {
        jsonRoot["attributes"]["updated"]
            = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
                parameters.SecretAttributes.Value().Updated.Value());
      }

      if (parameters.SecretAttributes.Value().RecoverableDays.HasValue())
      {
        jsonRoot["attributes"]["recoverableDays"]
            = parameters.SecretAttributes.Value().RecoverableDays.Value();
      }

      if (parameters.SecretAttributes.Value().RecoveryLevel.HasValue())
      {
        jsonRoot["attributes"]["recoveryLevel"]
            = parameters.SecretAttributes.Value().RecoveryLevel.Value().ToString();
      }
    }

    jsonBody = jsonRoot.dump();
  }

  Core::IO::MemoryBodyStream requestBody(
      reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());

  Core::Http::Request request(Core::Http::HttpMethod::Put, url, &requestBody);

  request.SetHeader("Content-Type", "application/json");
  request.SetHeader("Accept", "application/json");

  request.SetHeader("Content-Length", std::to_string(requestBody.Length()));

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::SecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::SecretBundle>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::DeletedSecretBundle>
KeyVaultClient::DeleteSecret(const std::string& secretName, const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Delete, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::DeletedSecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }

        if (jsonRoot.contains("recoveryId") && !jsonRoot["recoveryId"].is_null())
        {
          response.RecoveryId = jsonRoot["recoveryId"].get<std::string>();
        }

        if (jsonRoot.contains("scheduledPurgeDate") && !jsonRoot["scheduledPurgeDate"].is_null())
        {
          response.ScheduledPurgeDate = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
              jsonRoot["scheduledPurgeDate"].is_string()
                  ? std::stoll(jsonRoot["scheduledPurgeDate"].get<std::string>())
                  : jsonRoot["scheduledPurgeDate"].get<std::int64_t>());
        }

        if (jsonRoot.contains("deletedDate") && !jsonRoot["deletedDate"].is_null())
        {
          response.DeletedDate = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
              jsonRoot["deletedDate"].is_string()
                  ? std::stoll(jsonRoot["deletedDate"].get<std::string>())
                  : jsonRoot["deletedDate"].get<std::int64_t>());
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::DeletedSecretBundle>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::SecretBundle>
KeyVaultClient::UpdateSecret(
    const std::string& secretName,
    const std::string& secretVersion,
    const Models::SecretUpdateParameters& parameters,
    const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));
  if (secretVersion.empty())
  {
    throw std::invalid_argument("Parameter 'secretVersion' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretVersion));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  std::string jsonBody;
  {
    auto jsonRoot = Core::Json::_internal::json::object();
    if (parameters.ContentType.HasValue())
    {
      jsonRoot["contentType"] = parameters.ContentType.Value();
    }

    if (parameters.SecretAttributes.HasValue())
    {
      if (parameters.SecretAttributes.Value().Enabled.HasValue())
      {
        jsonRoot["attributes"]["enabled"] = parameters.SecretAttributes.Value().Enabled.Value();
      }

      if (parameters.SecretAttributes.Value().NotBefore.HasValue())
      {
        jsonRoot["attributes"]["nbf"] = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
            parameters.SecretAttributes.Value().NotBefore.Value());
      }

      if (parameters.SecretAttributes.Value().Expires.HasValue())
      {
        jsonRoot["attributes"]["exp"] = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
            parameters.SecretAttributes.Value().Expires.Value());
      }

      if (parameters.SecretAttributes.Value().Created.HasValue())
      {
        jsonRoot["attributes"]["created"]
            = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
                parameters.SecretAttributes.Value().Created.Value());
      }

      if (parameters.SecretAttributes.Value().Updated.HasValue())
      {
        jsonRoot["attributes"]["updated"]
            = Core::_internal::PosixTimeConverter::DateTimeToPosixTime(
                parameters.SecretAttributes.Value().Updated.Value());
      }

      if (parameters.SecretAttributes.Value().RecoverableDays.HasValue())
      {
        jsonRoot["attributes"]["recoverableDays"]
            = parameters.SecretAttributes.Value().RecoverableDays.Value();
      }

      if (parameters.SecretAttributes.Value().RecoveryLevel.HasValue())
      {
        jsonRoot["attributes"]["recoveryLevel"]
            = parameters.SecretAttributes.Value().RecoveryLevel.Value().ToString();
      }
    }

    if (parameters.Tags.HasValue())
    {
      jsonRoot["tags"] = Core::Json::_internal::json::object();

      for (auto const& kv : parameters.Tags.Value())
      {
        jsonRoot["tags"][kv.first] = kv.second;
      }
    }

    jsonBody = jsonRoot.dump();
  }

  Core::IO::MemoryBodyStream requestBody(
      reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());

  Core::Http::Request request(Core::Http::HttpMethod::Patch, url, &requestBody);

  request.SetHeader("Content-Type", "application/json");
  request.SetHeader("Accept", "application/json");

  request.SetHeader("Content-Length", std::to_string(requestBody.Length()));

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::SecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::SecretBundle>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::SecretBundle>
KeyVaultClient::GetSecret(
    const std::string& secretName,
    const std::string& secretVersion,
    const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));
  if (secretVersion.empty())
  {
    throw std::invalid_argument("Parameter 'secretVersion' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretVersion));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Get, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::SecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::SecretBundle>(std::move(response), std::move(rawResponse));
}

GetSecretsPagedResponse KeyVaultClient::GetSecrets(
    const KeyVaultClientGetSecretsOptions& options,
    const Core::Context& context) const
{
  Core::Url url;
  if (options.NextPageToken.empty())
  {
    url = m_url;
    url.AppendPath("secrets");

    url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    if (options.Maxresults.HasValue())
    {
      url.AppendQueryParameter("maxresults", std::to_string(options.Maxresults.Value()));
    }
  }
  else
  {
    if (options.NextPageToken.find("https://") == 0 || options.NextPageToken.find("http://") == 0)
    {
      url = Core::Url(options.NextPageToken);
      if (url.GetPort() == 0 && m_url.GetPort() != 0 && url.GetHost() == m_url.GetHost())
      {
        url.SetPort(m_url.GetPort());
      }
    }
    else
    {
      url = Core::Url(
          m_url.GetScheme() + "://" + m_url.GetHost() + ':' + std::to_string(m_url.GetPort()) + '/'
          + (options.NextPageToken[0] == '/' ? options.NextPageToken.substr(1)
                                             : options.NextPageToken));
    }

    const auto qps = url.GetQueryParameters();
    if (qps.find("api-version") != qps.cend())
    {
      url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    }
  }

  Core::Http::Request request(Core::Http::HttpMethod::Get, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  GetSecretsPagedResponse response{};
  response.m_client = std::make_shared<KeyVaultClient>(*this);
  response.m_options = options;
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());
        if (jsonRoot.contains("nextLink") && !jsonRoot["nextLink"].is_null())
        {
          response.NextPageToken = jsonRoot["nextLink"].get<std::string>();
        }

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = std::vector<Models::SecretItem>{};

          for (auto const& jsonItem : jsonRoot["value"])
          {
            Models::SecretItem vectorItem{};

            if (jsonItem.contains("id") && !jsonItem["id"].is_null())
            {
              vectorItem.Id = jsonItem["id"].get<std::string>();
            }

            if (jsonItem.contains("attributes") && !jsonItem["attributes"].is_null())
            {
              vectorItem.Attributes = Models::SecretAttributes{};

              if (jsonItem["attributes"].contains("enabled")
                  && !jsonItem["attributes"]["enabled"].is_null())
              {
                vectorItem.Attributes.Value().Enabled
                    = jsonItem["attributes"]["enabled"].get<bool>();
              }

              if (jsonItem["attributes"].contains("nbf")
                  && !jsonItem["attributes"]["nbf"].is_null())
              {
                vectorItem.Attributes.Value().NotBefore
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["nbf"].is_string()
                            ? std::stoll(jsonItem["attributes"]["nbf"].get<std::string>())
                            : jsonItem["attributes"]["nbf"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("exp")
                  && !jsonItem["attributes"]["exp"].is_null())
              {
                vectorItem.Attributes.Value().Expires
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["exp"].is_string()
                            ? std::stoll(jsonItem["attributes"]["exp"].get<std::string>())
                            : jsonItem["attributes"]["exp"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("created")
                  && !jsonItem["attributes"]["created"].is_null())
              {
                vectorItem.Attributes.Value().Created
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["created"].is_string()
                            ? std::stoll(jsonItem["attributes"]["created"].get<std::string>())
                            : jsonItem["attributes"]["created"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("updated")
                  && !jsonItem["attributes"]["updated"].is_null())
              {
                vectorItem.Attributes.Value().Updated
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["updated"].is_string()
                            ? std::stoll(jsonItem["attributes"]["updated"].get<std::string>())
                            : jsonItem["attributes"]["updated"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("recoverableDays")
                  && !jsonItem["attributes"]["recoverableDays"].is_null())
              {
                vectorItem.Attributes.Value().RecoverableDays
                    = jsonItem["attributes"]["recoverableDays"].is_string()
                    ? std::stoi(jsonItem["attributes"]["recoverableDays"].get<std::string>())
                    : jsonItem["attributes"]["recoverableDays"].get<std::int32_t>();
              }

              if (jsonItem["attributes"].contains("recoveryLevel")
                  && !jsonItem["attributes"]["recoveryLevel"].is_null())
              {
                vectorItem.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                    jsonItem["attributes"]["recoveryLevel"].get<std::string>());
              }
            }

            if (jsonItem.contains("tags") && !jsonItem["tags"].is_null())
            {
              vectorItem.Tags = std::map<std::string, std::string>{};

              for (auto const& kv : jsonItem["tags"].items())
              {
                std::string value{};
                value = kv.value().get<std::string>();
                vectorItem.Tags.Value().emplace(kv.key(), value);
              }
            }

            if (jsonItem.contains("contentType") && !jsonItem["contentType"].is_null())
            {
              vectorItem.ContentType = jsonItem["contentType"].get<std::string>();
            }

            if (jsonItem.contains("managed") && !jsonItem["managed"].is_null())
            {
              vectorItem.Managed = jsonItem["managed"].get<bool>();
            }

            response.Value.Value().emplace_back(std::move(vectorItem));
          }
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  response.RawResponse = std::move(rawResponse);

  return response;
}

GetSecretVersionsPagedResponse KeyVaultClient::GetSecretVersions(
    const std::string& secretName,
    const KeyVaultClientGetSecretVersionsOptions& options,
    const Core::Context& context) const
{
  Core::Url url;
  if (options.NextPageToken.empty())
  {
    url = m_url;
    url.AppendPath("secrets/");
    if (secretName.empty())
    {
      throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
    }
    url.AppendPath(Core::Url::Encode(secretName));
    url.AppendPath("versions");

    url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    if (options.Maxresults.HasValue())
    {
      url.AppendQueryParameter("maxresults", std::to_string(options.Maxresults.Value()));
    }
  }
  else
  {
    if (options.NextPageToken.find("https://") == 0 || options.NextPageToken.find("http://") == 0)
    {
      url = Core::Url(options.NextPageToken);
      if (url.GetPort() == 0 && m_url.GetPort() != 0 && url.GetHost() == m_url.GetHost())
      {
        url.SetPort(m_url.GetPort());
      }
    }
    else
    {
      url = Core::Url(
          m_url.GetScheme() + "://" + m_url.GetHost() + ':' + std::to_string(m_url.GetPort()) + '/'
          + (options.NextPageToken[0] == '/' ? options.NextPageToken.substr(1)
                                             : options.NextPageToken));
    }

    const auto qps = url.GetQueryParameters();
    if (qps.find("api-version") != qps.cend())
    {
      url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    }
  }

  Core::Http::Request request(Core::Http::HttpMethod::Get, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  GetSecretVersionsPagedResponse response{};
  response.m_client = std::make_shared<KeyVaultClient>(*this);
  response.m_secretName = secretName;
  response.m_options = options;
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());
        if (jsonRoot.contains("nextLink") && !jsonRoot["nextLink"].is_null())
        {
          response.NextPageToken = jsonRoot["nextLink"].get<std::string>();
        }

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = std::vector<Models::SecretItem>{};

          for (auto const& jsonItem : jsonRoot["value"])
          {
            Models::SecretItem vectorItem{};

            if (jsonItem.contains("id") && !jsonItem["id"].is_null())
            {
              vectorItem.Id = jsonItem["id"].get<std::string>();
            }

            if (jsonItem.contains("attributes") && !jsonItem["attributes"].is_null())
            {
              vectorItem.Attributes = Models::SecretAttributes{};

              if (jsonItem["attributes"].contains("enabled")
                  && !jsonItem["attributes"]["enabled"].is_null())
              {
                vectorItem.Attributes.Value().Enabled
                    = jsonItem["attributes"]["enabled"].get<bool>();
              }

              if (jsonItem["attributes"].contains("nbf")
                  && !jsonItem["attributes"]["nbf"].is_null())
              {
                vectorItem.Attributes.Value().NotBefore
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["nbf"].is_string()
                            ? std::stoll(jsonItem["attributes"]["nbf"].get<std::string>())
                            : jsonItem["attributes"]["nbf"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("exp")
                  && !jsonItem["attributes"]["exp"].is_null())
              {
                vectorItem.Attributes.Value().Expires
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["exp"].is_string()
                            ? std::stoll(jsonItem["attributes"]["exp"].get<std::string>())
                            : jsonItem["attributes"]["exp"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("created")
                  && !jsonItem["attributes"]["created"].is_null())
              {
                vectorItem.Attributes.Value().Created
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["created"].is_string()
                            ? std::stoll(jsonItem["attributes"]["created"].get<std::string>())
                            : jsonItem["attributes"]["created"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("updated")
                  && !jsonItem["attributes"]["updated"].is_null())
              {
                vectorItem.Attributes.Value().Updated
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["updated"].is_string()
                            ? std::stoll(jsonItem["attributes"]["updated"].get<std::string>())
                            : jsonItem["attributes"]["updated"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("recoverableDays")
                  && !jsonItem["attributes"]["recoverableDays"].is_null())
              {
                vectorItem.Attributes.Value().RecoverableDays
                    = jsonItem["attributes"]["recoverableDays"].is_string()
                    ? std::stoi(jsonItem["attributes"]["recoverableDays"].get<std::string>())
                    : jsonItem["attributes"]["recoverableDays"].get<std::int32_t>();
              }

              if (jsonItem["attributes"].contains("recoveryLevel")
                  && !jsonItem["attributes"]["recoveryLevel"].is_null())
              {
                vectorItem.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                    jsonItem["attributes"]["recoveryLevel"].get<std::string>());
              }
            }

            if (jsonItem.contains("tags") && !jsonItem["tags"].is_null())
            {
              vectorItem.Tags = std::map<std::string, std::string>{};

              for (auto const& kv : jsonItem["tags"].items())
              {
                std::string value{};
                value = kv.value().get<std::string>();
                vectorItem.Tags.Value().emplace(kv.key(), value);
              }
            }

            if (jsonItem.contains("contentType") && !jsonItem["contentType"].is_null())
            {
              vectorItem.ContentType = jsonItem["contentType"].get<std::string>();
            }

            if (jsonItem.contains("managed") && !jsonItem["managed"].is_null())
            {
              vectorItem.Managed = jsonItem["managed"].get<bool>();
            }

            response.Value.Value().emplace_back(std::move(vectorItem));
          }
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  response.RawResponse = std::move(rawResponse);

  return response;
}

GetDeletedSecretsPagedResponse KeyVaultClient::GetDeletedSecrets(
    const KeyVaultClientGetDeletedSecretsOptions& options,
    const Core::Context& context) const
{
  Core::Url url;
  if (options.NextPageToken.empty())
  {
    url = m_url;
    url.AppendPath("deletedsecrets");

    url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    if (options.Maxresults.HasValue())
    {
      url.AppendQueryParameter("maxresults", std::to_string(options.Maxresults.Value()));
    }
  }
  else
  {
    if (options.NextPageToken.find("https://") == 0 || options.NextPageToken.find("http://") == 0)
    {
      url = Core::Url(options.NextPageToken);
      if (url.GetPort() == 0 && m_url.GetPort() != 0 && url.GetHost() == m_url.GetHost())
      {
        url.SetPort(m_url.GetPort());
      }
    }
    else
    {
      url = Core::Url(
          m_url.GetScheme() + "://" + m_url.GetHost() + ':' + std::to_string(m_url.GetPort()) + '/'
          + (options.NextPageToken[0] == '/' ? options.NextPageToken.substr(1)
                                             : options.NextPageToken));
    }

    const auto qps = url.GetQueryParameters();
    if (qps.find("api-version") != qps.cend())
    {
      url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));
    }
  }

  Core::Http::Request request(Core::Http::HttpMethod::Get, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  GetDeletedSecretsPagedResponse response{};
  response.m_client = std::make_shared<KeyVaultClient>(*this);
  response.m_options = options;
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());
        if (jsonRoot.contains("nextLink") && !jsonRoot["nextLink"].is_null())
        {
          response.NextPageToken = jsonRoot["nextLink"].get<std::string>();
        }

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = std::vector<Models::DeletedSecretItem>{};

          for (auto const& jsonItem : jsonRoot["value"])
          {
            Models::DeletedSecretItem vectorItem{};

            if (jsonItem.contains("id") && !jsonItem["id"].is_null())
            {
              vectorItem.Id = jsonItem["id"].get<std::string>();
            }

            if (jsonItem.contains("attributes") && !jsonItem["attributes"].is_null())
            {
              vectorItem.Attributes = Models::SecretAttributes{};

              if (jsonItem["attributes"].contains("enabled")
                  && !jsonItem["attributes"]["enabled"].is_null())
              {
                vectorItem.Attributes.Value().Enabled
                    = jsonItem["attributes"]["enabled"].get<bool>();
              }

              if (jsonItem["attributes"].contains("nbf")
                  && !jsonItem["attributes"]["nbf"].is_null())
              {
                vectorItem.Attributes.Value().NotBefore
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["nbf"].is_string()
                            ? std::stoll(jsonItem["attributes"]["nbf"].get<std::string>())
                            : jsonItem["attributes"]["nbf"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("exp")
                  && !jsonItem["attributes"]["exp"].is_null())
              {
                vectorItem.Attributes.Value().Expires
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["exp"].is_string()
                            ? std::stoll(jsonItem["attributes"]["exp"].get<std::string>())
                            : jsonItem["attributes"]["exp"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("created")
                  && !jsonItem["attributes"]["created"].is_null())
              {
                vectorItem.Attributes.Value().Created
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["created"].is_string()
                            ? std::stoll(jsonItem["attributes"]["created"].get<std::string>())
                            : jsonItem["attributes"]["created"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("updated")
                  && !jsonItem["attributes"]["updated"].is_null())
              {
                vectorItem.Attributes.Value().Updated
                    = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                        jsonItem["attributes"]["updated"].is_string()
                            ? std::stoll(jsonItem["attributes"]["updated"].get<std::string>())
                            : jsonItem["attributes"]["updated"].get<std::int64_t>());
              }

              if (jsonItem["attributes"].contains("recoverableDays")
                  && !jsonItem["attributes"]["recoverableDays"].is_null())
              {
                vectorItem.Attributes.Value().RecoverableDays
                    = jsonItem["attributes"]["recoverableDays"].is_string()
                    ? std::stoi(jsonItem["attributes"]["recoverableDays"].get<std::string>())
                    : jsonItem["attributes"]["recoverableDays"].get<std::int32_t>();
              }

              if (jsonItem["attributes"].contains("recoveryLevel")
                  && !jsonItem["attributes"]["recoveryLevel"].is_null())
              {
                vectorItem.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                    jsonItem["attributes"]["recoveryLevel"].get<std::string>());
              }
            }

            if (jsonItem.contains("tags") && !jsonItem["tags"].is_null())
            {
              vectorItem.Tags = std::map<std::string, std::string>{};

              for (auto const& kv : jsonItem["tags"].items())
              {
                std::string value{};
                value = kv.value().get<std::string>();
                vectorItem.Tags.Value().emplace(kv.key(), value);
              }
            }

            if (jsonItem.contains("contentType") && !jsonItem["contentType"].is_null())
            {
              vectorItem.ContentType = jsonItem["contentType"].get<std::string>();
            }

            if (jsonItem.contains("managed") && !jsonItem["managed"].is_null())
            {
              vectorItem.Managed = jsonItem["managed"].get<bool>();
            }

            if (jsonItem.contains("recoveryId") && !jsonItem["recoveryId"].is_null())
            {
              vectorItem.RecoveryId = jsonItem["recoveryId"].get<std::string>();
            }

            if (jsonItem.contains("scheduledPurgeDate")
                && !jsonItem["scheduledPurgeDate"].is_null())
            {
              vectorItem.ScheduledPurgeDate
                  = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                      jsonItem["scheduledPurgeDate"].is_string()
                          ? std::stoll(jsonItem["scheduledPurgeDate"].get<std::string>())
                          : jsonItem["scheduledPurgeDate"].get<std::int64_t>());
            }

            if (jsonItem.contains("deletedDate") && !jsonItem["deletedDate"].is_null())
            {
              vectorItem.DeletedDate = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                  jsonItem["deletedDate"].is_string()
                      ? std::stoll(jsonItem["deletedDate"].get<std::string>())
                      : jsonItem["deletedDate"].get<std::int64_t>());
            }

            response.Value.Value().emplace_back(std::move(vectorItem));
          }
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  response.RawResponse = std::move(rawResponse);

  return response;
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::DeletedSecretBundle>
KeyVaultClient::GetDeletedSecret(const std::string& secretName, const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("deletedsecrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Get, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::DeletedSecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }

        if (jsonRoot.contains("recoveryId") && !jsonRoot["recoveryId"].is_null())
        {
          response.RecoveryId = jsonRoot["recoveryId"].get<std::string>();
        }

        if (jsonRoot.contains("scheduledPurgeDate") && !jsonRoot["scheduledPurgeDate"].is_null())
        {
          response.ScheduledPurgeDate = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
              jsonRoot["scheduledPurgeDate"].is_string()
                  ? std::stoll(jsonRoot["scheduledPurgeDate"].get<std::string>())
                  : jsonRoot["scheduledPurgeDate"].get<std::int64_t>());
        }

        if (jsonRoot.contains("deletedDate") && !jsonRoot["deletedDate"].is_null())
        {
          response.DeletedDate = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
              jsonRoot["deletedDate"].is_string()
                  ? std::stoll(jsonRoot["deletedDate"].get<std::string>())
                  : jsonRoot["deletedDate"].get<std::int64_t>());
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::DeletedSecretBundle>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::PurgeDeletedSecretResult>
KeyVaultClient::PurgeDeletedSecret(const std::string& secretName, const Core::Context& context)
    const
{
  auto url = m_url;
  url.AppendPath("deletedsecrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Delete, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::NoContent)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::PurgeDeletedSecretResult response{};

  return Response<Models::PurgeDeletedSecretResult>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::SecretBundle>
KeyVaultClient::RecoverDeletedSecret(const std::string& secretName, const Core::Context& context)
    const
{
  auto url = m_url;
  url.AppendPath("deletedsecrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));
  url.AppendPath("recover");

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Post, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::SecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::SecretBundle>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::BackupSecretResult>
KeyVaultClient::BackupSecret(const std::string& secretName, const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/");
  if (secretName.empty())
  {
    throw std::invalid_argument("Parameter 'secretName' cannot be an empty string.");
  }
  url.AppendPath(Core::Url::Encode(secretName));
  url.AppendPath("backup");

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  Core::Http::Request request(Core::Http::HttpMethod::Post, url);

  request.SetHeader("Accept", "application/json");

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::BackupSecretResult response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value
              = Core::_internal::Base64Url::Base64UrlDecode(jsonRoot["value"].get<std::string>());
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::BackupSecretResult>(std::move(response), std::move(rawResponse));
}

Azure::Response<Azure::Security::KeyVault::Secrets::_detail::Models::SecretBundle>
KeyVaultClient::RestoreSecret(
    const Models::SecretRestoreParameters& parameters,
    const Core::Context& context) const
{
  auto url = m_url;
  url.AppendPath("secrets/restore");

  url.AppendQueryParameter("api-version", Core::Url::Encode(m_apiVersion));

  std::string jsonBody;
  {
    auto jsonRoot = Core::Json::_internal::json::object();
    jsonRoot["value"] = Core::_internal::Base64Url::Base64UrlEncode(parameters.SecretBundleBackup);
    jsonBody = jsonRoot.dump();
  }

  Core::IO::MemoryBodyStream requestBody(
      reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());

  Core::Http::Request request(Core::Http::HttpMethod::Post, url, &requestBody);

  request.SetHeader("Content-Type", "application/json");
  request.SetHeader("Accept", "application/json");

  request.SetHeader("Content-Length", std::to_string(requestBody.Length()));

  auto rawResponse = m_pipeline->Send(request, context);
  const auto httpStatusCode = rawResponse->GetStatusCode();

  if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
  {
    throw Core::RequestFailedException(rawResponse);
  }

  Models::SecretBundle response{};
  {
    const auto& responseBody = rawResponse->GetBody();
    if (responseBody.size() > 0)
    {
      try
      {
        const auto jsonRoot
            = Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());

        if (jsonRoot.contains("value") && !jsonRoot["value"].is_null())
        {
          response.Value = jsonRoot["value"].get<std::string>();
        }

        if (jsonRoot.contains("id") && !jsonRoot["id"].is_null())
        {
          response.Id = jsonRoot["id"].get<std::string>();
        }

        if (jsonRoot.contains("contentType") && !jsonRoot["contentType"].is_null())
        {
          response.ContentType = jsonRoot["contentType"].get<std::string>();
        }

        if (jsonRoot.contains("attributes") && !jsonRoot["attributes"].is_null())
        {
          response.Attributes = Models::SecretAttributes{};

          if (jsonRoot["attributes"].contains("enabled")
              && !jsonRoot["attributes"]["enabled"].is_null())
          {
            response.Attributes.Value().Enabled = jsonRoot["attributes"]["enabled"].get<bool>();
          }

          if (jsonRoot["attributes"].contains("nbf") && !jsonRoot["attributes"]["nbf"].is_null())
          {
            response.Attributes.Value().NotBefore
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["nbf"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["nbf"].get<std::string>())
                        : jsonRoot["attributes"]["nbf"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("exp") && !jsonRoot["attributes"]["exp"].is_null())
          {
            response.Attributes.Value().Expires
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["exp"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["exp"].get<std::string>())
                        : jsonRoot["attributes"]["exp"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("created")
              && !jsonRoot["attributes"]["created"].is_null())
          {
            response.Attributes.Value().Created
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["created"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["created"].get<std::string>())
                        : jsonRoot["attributes"]["created"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("updated")
              && !jsonRoot["attributes"]["updated"].is_null())
          {
            response.Attributes.Value().Updated
                = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
                    jsonRoot["attributes"]["updated"].is_string()
                        ? std::stoll(jsonRoot["attributes"]["updated"].get<std::string>())
                        : jsonRoot["attributes"]["updated"].get<std::int64_t>());
          }

          if (jsonRoot["attributes"].contains("recoverableDays")
              && !jsonRoot["attributes"]["recoverableDays"].is_null())
          {
            response.Attributes.Value().RecoverableDays
                = jsonRoot["attributes"]["recoverableDays"].is_string()
                ? std::stoi(jsonRoot["attributes"]["recoverableDays"].get<std::string>())
                : jsonRoot["attributes"]["recoverableDays"].get<std::int32_t>();
          }

          if (jsonRoot["attributes"].contains("recoveryLevel")
              && !jsonRoot["attributes"]["recoveryLevel"].is_null())
          {
            response.Attributes.Value().RecoveryLevel = Models::DeletionRecoveryLevel(
                jsonRoot["attributes"]["recoveryLevel"].get<std::string>());
          }
        }

        if (jsonRoot.contains("tags") && !jsonRoot["tags"].is_null())
        {
          response.Tags = std::map<std::string, std::string>{};

          for (auto const& kv : jsonRoot["tags"].items())
          {
            std::string value{};
            value = kv.value().get<std::string>();
            response.Tags.Value().emplace(kv.key(), value);
          }
        }

        if (jsonRoot.contains("kid") && !jsonRoot["kid"].is_null())
        {
          response.Kid = jsonRoot["kid"].get<std::string>();
        }

        if (jsonRoot.contains("managed") && !jsonRoot["managed"].is_null())
        {
          response.Managed = jsonRoot["managed"].get<bool>();
        }
      }
      catch (Core::Json::_internal::json::exception const& ex)
      {
        throw Core::RequestFailedException(ex.what());
      }
    }
  }

  return Response<Models::SecretBundle>(std::move(response), std::move(rawResponse));
}
