#include "HybridDigest.hpp"
#include <NitroModules/ArrayBuffer.hpp>

#include <openssl/evp.h>

namespace icure::nitrokryptom::digest {

std::shared_ptr<margelo::nitro::ArrayBuffer> doDigest(const std::shared_ptr<margelo::nitro::ArrayBuffer>& data, const EVP_MD *type) {
    std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
    if (!ctx) throw std::runtime_error("Failed to create EVP_MD_CTX");
    
    if (1 != EVP_DigestInit_ex(ctx.get(), type, nullptr))
        throw std::runtime_error("EVP_DigestInit_ex failed");

    if (1 != EVP_DigestUpdate(ctx.get(), data->data(), data->size()))
        throw std::runtime_error("EVP_DigestUpdate failed");
    
    unsigned int bufferSize = EVP_MD_size(type);
    unsigned int writtenOut = bufferSize;
    uint8_t* hashBuffer = new uint8_t[bufferSize];
    
    int finalRes = EVP_DigestFinal_ex(ctx.get(), hashBuffer, &writtenOut);
    
    if (finalRes != 1) {
        delete[] hashBuffer;
        throw std::runtime_error("EVP_DigestFinal_ex failed");
    }
    
    return std::make_shared<margelo::nitro::NativeArrayBuffer>(hashBuffer, writtenOut, [=]() { delete[] hashBuffer; });
}
    
}


namespace margelo::nitro::nitrokryptom {

std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridDigest::sha512(const std::shared_ptr<ArrayBuffer>& data) {
    return Promise<std::shared_ptr<ArrayBuffer>>::resolved(icure::nitrokryptom::digest::doDigest(data, EVP_sha512()));
}
std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridDigest::sha256(const std::shared_ptr<ArrayBuffer>& data) {
    return Promise<std::shared_ptr<ArrayBuffer>>::resolved(icure::nitrokryptom::digest::doDigest(data, EVP_sha256()));
}

}
