#include "Utils.h"

#include <Lifecycle.h>

namespace sharedjsi
{
Function ditto_shutdown(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
                                          {
    ::ditto_shutdown(jsPointerObjectToCPointer<CDitto_t>(runtime, arguments[0]));
    return {};
  });
}

Function ditto_free(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
                                          {
    ::ditto_free(jsPointerObjectToCPointer<CDitto_t>(runtime, arguments[0]));
    return {};
  });
}

Function dittoffi_ditto_try_new_blocking(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
                                          {
    std::string path = jsTypedArrayToCString(runtime, arguments[0]);
    auto *identity_config = jsPointerObjectToCPointer<CIdentityConfig_t>(runtime, arguments[1]);
    std::string history_tracking_str = arguments[2].toString(runtime).utf8(runtime);
    std::string experimental_passphrase = jsTypedArrayToCString(runtime, arguments[3]);
    std::string transport_config_mode_str = arguments[4].toString(runtime).utf8(runtime);

    HistoryTracking_t history_tracking;
    if (history_tracking_str == "Disabled") {
      history_tracking = HISTORY_TRACKING_DISABLED;
    } else if (history_tracking_str == "Enabled") {
      history_tracking = HISTORY_TRACKING_ENABLED;
    } else {
        throw std::invalid_argument("Invalid history tracking mode provided");
    }

    TransportConfigMode_t transport_config_mode;
    if (transport_config_mode_str == "PlatformDependent") {
        transport_config_mode = TRANSPORT_CONFIG_MODE_PLATFORM_DEPENDENT;
    } else if (transport_config_mode_str == "PlatformIndependent") {
        transport_config_mode = TRANSPORT_CONFIG_MODE_PLATFORM_INDEPENDENT;
    } else {
        throw std::invalid_argument("Invalid transport configuration mode provided");
    }

    dittoffi_result_CDitto_ptr_t res = ::dittoffi_ditto_try_new_blocking(
        path.c_str(),
        identity_config,
        history_tracking,
        experimental_passphrase.empty() ? nullptr: experimental_passphrase.c_str(),
        transport_config_mode
    );
    Object obj(runtime);
    obj.setProperty(runtime, "success", cPointerToJSPointerObject(runtime, res.success));
    obj.setProperty(runtime, "error", cPointerToJSPointerObject(runtime, res.error));
    return obj;
  });
}


Function ditto_init_sdk_version(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
                                          {
    std::string platform_str = arguments[0].toString(runtime).utf8(runtime);
    std::string language_str = arguments[1].toString(runtime).utf8(runtime);
    std::string semver_str = arguments[2].toString(runtime).utf8(runtime);
    const char *semver = semver_str.c_str();

    Language_t language = LANGUAGE_UNKNOWN;
    if (language_str == "JavaScript") {
      language = LANGUAGE_JAVA_SCRIPT;
    }

    Platform_t platform = PLATFORM_UNKNOWN;
    if (platform_str == "Ios") {
      platform = PLATFORM_IOS;
    } else if (platform_str == "Android") {
      platform = PLATFORM_ANDROID;
    }

    ::ditto_init_sdk_version(platform, language, semver);
    return {};
  });
}

}
