#pragma once

#include <memory>
#include <openssl/evp.h>
#include <string>

#include "HybridSlhDsaKeyPairSpec.hpp"

namespace margelo::nitro::crypto {

class HybridSlhDsaKeyPair : public HybridSlhDsaKeyPairSpec {
 public:
  HybridSlhDsaKeyPair() : HybridObject(TAG) {}
  ~HybridSlhDsaKeyPair() override = default;

  std::shared_ptr<Promise<void>> generateKeyPair(double publicFormat, double publicType, double privateFormat, double privateType) override;

  void generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType) override;

  std::shared_ptr<ArrayBuffer> getPublicKey() override;
  std::shared_ptr<ArrayBuffer> getPrivateKey() override;

  std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> sign(const std::shared_ptr<ArrayBuffer>& message) override;

  std::shared_ptr<ArrayBuffer> signSync(const std::shared_ptr<ArrayBuffer>& message) override;

  std::shared_ptr<Promise<bool>> verify(const std::shared_ptr<ArrayBuffer>& signature,
                                        const std::shared_ptr<ArrayBuffer>& message) override;

  bool verifySync(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message) override;

  void setVariant(const std::string& variant) override;

 private:
  using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;

  std::string variant_;
  EVP_PKEY_ptr pkey_{nullptr, EVP_PKEY_free};

  int publicFormat_ = -1;
  int publicType_ = -1;
  int privateFormat_ = -1;
  int privateType_ = -1;

  void checkKeyPair();
};

} // namespace margelo::nitro::crypto
