#include <vereign/identity/provider.hh>

#include <vereign/crypto/digest.hh>
#include <vereign/crypto/bio.hh>
#include <vereign/crypto/rsa.hh>
#include <vereign/encoding/base64.hh>

namespace {
  constexpr int rsaKeySizeBits = 2048;
}

namespace vereign::identity {

Provider::Provider(kvstore::CryptoStorage& storage)
  : storage_{storage}
{}

Provider::~Provider() = default;

auto Provider::ResetIdentity(const std::string& pin) -> std::string {
  std::lock_guard<std::mutex> l{mu_};

  storage_.Reset(pin);

  auto rsa = crypto::rsa::GenerateKey(rsaKeySizeBits);

  auto private_key = crypto::rsa::ExportPrivateKeyToPEM(rsa.get());
  storage_.PutBytes("identity_private_key", crypto::bio::View(private_key.get()));

  auto public_key = crypto::rsa::ExportPublicKeyToPEM(rsa.get());
  storage_.PutBytes("identity_public_key", crypto::bio::View(public_key.get()));

  bytes::Buffer encoded;
  encoding::base64::Encode(crypto::bio::View(public_key.get()), encoded);

  return std::string{encoded.View().String()};
}

auto Provider::LoadIdentity(const std::string& pin) -> std::string {
  std::lock_guard<std::mutex> l{mu_};

  storage_.Open(pin);

  bytes::Buffer public_key;
  storage_.GetBytes("identity_public_key", public_key);

  bytes::Buffer encoded;
  encoding::base64::Encode(public_key.View(), encoded);

  return std::string(encoded.View().String());
}

auto Provider::GetIdentityPublicKeyBase64() -> std::string {
  std::lock_guard<std::mutex> l{mu_};

  bytes::Buffer public_key;
  storage_.GetBytes("identity_public_key", public_key);

  bytes::Buffer encoded;
  encoding::base64::Encode(public_key.View(), encoded);

  return std::string(encoded.View().String());
}

auto Provider::GetDeviceHash() -> std::string {
  std::lock_guard<std::mutex> l{mu_};

  bytes::Buffer public_key;
  storage_.GetBytes("identity_public_key", public_key);

  bytes::Buffer hash;
  crypto::digest::sha1(public_key.View(), hash);

  bytes::Buffer encoded;
  encoding::base64::Encode(hash.View(), encoded);

  return std::string(encoded.View().String());
}

} // namespace vereign::identity