#include "Utils.h"

#include <Collection.h>

namespace sharedjsi
{

Function ditto_collection_insert_value(Runtime &runtime)
{
  return Function::createFromHostFunction(runtime,
                                          PropNameID::forAscii(runtime,
                                                               STRINGIFIED_FUNC_NAME()),
                                          0,
                                          [](Runtime &runtime,
                                             const Value &thisValue,
                                             const Value *arguments,
                                             size_t count) -> Value
                                          {
    auto *ditto = jsPointerObjectToCPointer<CDitto_t>(runtime, arguments[0]);

    std::string collection_name_str = jsTypedArrayToCString(runtime, arguments[1]);
    const char *collectionName = collection_name_str.c_str();

    TypedArrayBase typedArrayBase(runtime, arguments[2].asObject(runtime));
    std::vector<uint8_t> docCborVector = typedArrayBase.toVector(runtime);
    slice_ref_uint8_t docCbor = { .ptr = docCborVector.data(), .len = docCborVector.size() };

    WriteStrategyRs_t writeStrategy;
    std::string writeStrategyStr = arguments[3].asString(runtime).utf8(runtime);

    if (writeStrategyStr == "Merge") {
      writeStrategy = WRITE_STRATEGY_RS_MERGE;
    } else if (writeStrategyStr == "InsertIfAbsent") {
      writeStrategy = WRITE_STRATEGY_RS_INSERT_IF_ABSENT;
    } else if (writeStrategyStr == "InsertDefaultIfAbsent") {
      writeStrategy = WRITE_STRATEGY_RS_INSERT_DEFAULT_IF_ABSENT;
    } else if (writeStrategyStr == "UpdateDifferentValues") {
      writeStrategy = WRITE_STRATEGY_RS_UPDATE_DIFFERENT_VALUES;
    } else {
      throw std::invalid_argument("Invalid write strategy");
    }

    std::string log_hint_str = jsTypedArrayToCString(runtime, arguments[4]);
    const char *log_hint = log_hint_str.c_str();

    auto *writeTransaction = jsPointerObjectToCPointer<CWriteTransaction_t>(runtime, arguments[5]);

    DocIdResult_t res = ::ditto_collection_insert_value(ditto, collectionName, docCbor, writeStrategy, log_hint, writeTransaction);

    Object obj(runtime);
    obj.setProperty(runtime, "status_code", static_cast<double>(res.status_code));
    obj.setProperty(runtime, "id", pointerToHexString(res.id.ptr));
    return obj;
  });
}
}
