// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
 * @brief This tool helps cleanup resources (keys, certificates, secrets) existing in a key vault,
 * Attempts to restore it as close to original as possible without having to recreate the key vault.
 *
 * @remark The following environment variables must be set before running the sample.
 * - AZURE_KEYVAULT_URL:  To the Key Vault account URL.
 *
 */

#include <azure/identity.hpp>
#include <azure/keyvault/certificates.hpp>
#include <azure/keyvault/keys.hpp>
#include <azure/keyvault/secrets.hpp>

#include <chrono>
#include <iostream>

using namespace Azure::Security::KeyVault::Secrets;
using namespace Azure::Security::KeyVault::Certificates;
using namespace Azure::Security::KeyVault::Keys;
using namespace std::chrono_literals;

int main()
{
  auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();

  SecretClient secretClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
  KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
  CertificateClient certClient(std::getenv("AZURE_KEYVAULT_URL"), credential);

  try
  {
    std::vector<DeleteCertificateOperation> certOps;
    std::vector<DeleteKeyOperation> keyOps;
    std::vector<DeleteSecretOperation> secretOps;

    for (auto secrets = secretClient.GetPropertiesOfSecrets(); secrets.HasPage();
         secrets.MoveToNextPage())
    {
      for (auto const& secret : secrets.Items)
      {
        try
        {
          secretOps.push_back(secretClient.StartDeleteSecret(secret.Name));
          std::cout << "DeleteSecret" << secret.Name << std::endl;
        }
        catch (...)
        {
          std::cout << "fail to delete secret " << secret.Name;
        }
      }
    }

    for (auto certificates = certClient.GetPropertiesOfCertificates(); certificates.HasPage();
         certificates.MoveToNextPage())
    {
      for (auto const& certificate : certificates.Items)
      {
        try
        {
          certOps.push_back(certClient.StartDeleteCertificate(certificate.Name));
          std::cout << "Delete Certificate" << certificate.Name << std::endl;
        }
        catch (...)
        {
          std::cout << "fail to delete cert " << certificate.Name;
        }
      }
    }

    for (auto keys = keyClient.GetPropertiesOfKeys(); keys.HasPage(); keys.MoveToNextPage())
    {
      for (auto const& key : keys.Items)
      {
        try
        {
          keyOps.push_back(keyClient.StartDeleteKey(key.Name));
          std::cout << "DeleteKey" << key.Name << std::endl;
        }
        catch (...)
        {
          std::cout << "fail to delete key " << key.Name;
        }
      }
    }

    for (auto op : certOps)
    {
      op.PollUntilDone(1s);
      certClient.PurgeDeletedCertificate(op.Value().Name());
      std::cout << "Purge cert " << op.Value().Name() << std::endl;
    }

    for (auto op : secretOps)
    {
      op.PollUntilDone(1s);
      secretClient.PurgeDeletedSecret(op.Value().Name);
      std::cout << "Purge secret " << op.Value().Name << std::endl;
    }

    for (auto op : keyOps)
    {
      op.PollUntilDone(1s);
      keyClient.PurgeDeletedKey(op.Value().Name());
      std::cout << "Purge Key " << op.Value().Name() << std::endl;
    }
  }
  catch (Azure::Core::Credentials::AuthenticationException const& e)
  {
    std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
    return 1;
  }
  catch (Azure::Core::RequestFailedException const& e)
  {
    std::cout << "Key Vault Secret Client Exception happened:" << std::endl
              << e.Message << std::endl;
    return 1;
  }

  return 0;
}
