#include "randomx.h"
#include "web_randomx.h"
#include <cstddef>

static randomx_cache* cache = nullptr;
static randomx_vm* vm = nullptr;

// JS calls with (variant, height, seed_ptr)
EM_PORT_API(void) web_randomx_init_cache(int variant, uint64_t height, const void* seed) {
    if (cache == nullptr) {
        cache = randomx_alloc_cache(RANDOMX_FLAG_DEFAULT);
        if (cache == nullptr) {
            return;
        }
    }
    randomx_init_cache(cache, seed, 32);
}

EM_PORT_API(void) web_randomx_create_vm() {
    if (vm != nullptr) {
        // If we have a VM, just ensure its cache is up to date.
        if (cache != nullptr) {
            randomx_vm_set_cache(vm, cache);
        }
        return;
    }
    vm = randomx_create_vm(RANDOMX_FLAG_DEFAULT, cache, nullptr);
}

// JS calls with (variant, height, seed_ptr, input_ptr, input_size, output_ptr)
EM_PORT_API(void) web_randomx_hash(int variant, uint64_t height, const void* seed, const void* input, size_t inputSize, void* output) {
    if (vm == nullptr) {
        if (cache == nullptr) {
            web_randomx_init_cache(variant, height, seed);
        };
        web_randomx_create_vm();
        if (vm == nullptr) return;
    }
    // The JS seems to re-initialize cache on every job. Let's ensure VM has the latest cache.
    randomx_vm_set_cache(vm, cache);
    randomx_calculate_hash(vm, input, inputSize, output);
}

EM_PORT_API(void) web_randomx_release_cache() {
    if (cache != nullptr) {
        randomx_release_cache(cache);
        cache = nullptr;
    }
}

EM_PORT_API(void) web_randomx_destroy_vm() {
    if (vm != nullptr) {
        randomx_destroy_vm(vm);
        vm = nullptr;
    }
}
