//
// Created by #Suyghur, on 2021/06/09.
//

#include <jni.h>
#include <toolkit.h>
#include <comm_map.h>
#include <params_kit.h>
#include <md5/md5.h>
#include <logger.h>
#include <aes/aes_utils.h>

#ifdef __cplusplus
extern "C" {
#endif

static void InitSdkDrive(JNIEnv *env, jobject thiz, jobject context) {
    CommMap::GetInstance()->Init(env, context);
    Logger::is_debug = ParamsKit::GetDebugModel(env, context);
}

static void SetCommParam(JNIEnv *env, jobject thiz, jstring key, jstring value) {
    std::string key_ = ToolKit::JString2String(env, key);
    std::string value_ = ToolKit::JString2String(env, value);
    if (key_ == "device_id") {
        if (value_ == CommMap::GetInstance()->comm_params["android_id"].asString()) {
            CommMap::GetInstance()->comm_params["id_type"] = 1;
        } else {
            CommMap::GetInstance()->comm_params["id_type"] = 0;
        }
    }
    CommMap::GetInstance()->comm_params[key_] = value_;
}

static jstring GetCommParam(JNIEnv *env, jobject thiz, jstring key) {
    std::string key_ = ToolKit::JString2String(env, key);
    return env->NewStringUTF(CommMap::GetInstance()->comm_params[key_].asString().c_str());
}

static void SetCoreParam(JNIEnv *env, jobject thiz, jstring key, jstring value) {
    std::string key_ = ToolKit::JString2String(env, key);
    std::string value_ = ToolKit::JString2String(env, value);
    if (key_ == "device_id") {
        if (value_ == CommMap::GetInstance()->core_params["android_id"].asString()) {
            CommMap::GetInstance()->core_params["id_type"] = 1;
        } else {
            CommMap::GetInstance()->core_params["id_type"] = 0;
        }
    }
    CommMap::GetInstance()->core_params[key_] = value_;
}

static jstring GetCoreParam(JNIEnv *env, jobject thiz, jstring key) {
    std::string key_ = ToolKit::JString2String(env, key);
    return env->NewStringUTF(CommMap::GetInstance()->core_params[key_].asString().c_str());
}

static jstring InvokeCommJob(JNIEnv *env, jobject thiz, jstring key, jstring data) {
    const char *key_ = env->GetStringUTFChars(key, JNI_FALSE);
    const char *data_ = env->GetStringUTFChars(data, JNI_FALSE);

    //添加公共参数
    Json::Value root = ToolKit::ToJsonObject(data_);
    root["common"] = CommMap::GetInstance()->comm_params;

    Logger::D(env, "请求参数 : " + ToolKit::ToJsonString(root));

    char *p = AesUtils::Encrypt(ToolKit::ToJsonString(root).c_str(), reinterpret_cast<const uint8_t *>(key_));
    jstring result = ToolKit::GetJString(env, p);
    env->ReleaseStringUTFChars(key, key_);
    env->ReleaseStringUTFChars(data, data_);
    free(p);
    return result;
}

static jstring InvokeCoreJob(JNIEnv *env, jobject thiz, jstring key, jstring data) {
    const char *key_ = env->GetStringUTFChars(key, JNI_FALSE);
    const char *data_ = env->GetStringUTFChars(data, JNI_FALSE);

    //添加公共参数
    Json::Value root = ToolKit::ToJsonObject(data_);
    root["common"] = CommMap::GetInstance()->core_params;

    Logger::D(env, "请求参数 : " + ToolKit::ToJsonString(root));

    char *p = AesUtils::Encrypt(ToolKit::ToJsonString(root).c_str(), reinterpret_cast<const uint8_t *>(key_));
    jstring result = ToolKit::GetJString(env, p);
    env->ReleaseStringUTFChars(key, key_);
    env->ReleaseStringUTFChars(data, data_);
    free(p);
    return result;
}

static jstring ParseJob(JNIEnv *env, jobject thiz, jstring key, jstring data) {
    const char *key_ = env->GetStringUTFChars(key, JNI_FALSE);
    const char *data_ = env->GetStringUTFChars(data, JNI_FALSE);
    char *raw = AesUtils::Decrypt(data_, reinterpret_cast<const uint8_t *>(key_));
    Logger::D(env, raw);
    jstring result = ToolKit::GetJString(env, raw);
    env->ReleaseStringUTFChars(key, key_);
    env->ReleaseStringUTFChars(data, data_);
    free(raw);
    return result;
}

static jstring GetCommMap(JNIEnv *env, jobject thiz) {
    Json::Value root;
    root["common"] = CommMap::GetInstance()->comm_params;
    jstring data = ToolKit::GetJString(env, ToolKit::ToJsonString(root).c_str());
    return data;
}

static jstring GetCoreMap(JNIEnv *env, jobject thiz) {
    Json::Value root;
    root["common"] = CommMap::GetInstance()->core_params;
    jstring data = ToolKit::GetJString(env, ToolKit::ToJsonString(root).c_str());
    return data;
}

static JNINativeMethod gMethod[] = {
        {"initSdkDrive",  "(Landroid/content/Context;)V",                             (void *) InitSdkDrive},
        {"setCommParam",  "(Ljava/lang/String;Ljava/lang/String;)V",                  (void *) SetCommParam},
        {"getCommParam",  "(Ljava/lang/String;)Ljava/lang/String;",                   (void *) GetCommParam},
        {"setCoreParam",  "(Ljava/lang/String;Ljava/lang/String;)V",                  (void *) SetCoreParam},
        {"getCoreParam",  "(Ljava/lang/String;)Ljava/lang/String;",                   (void *) GetCommParam},
        {"invokeCommJob", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void *) InvokeCommJob},
        {"invokeCoreJob", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void *) InvokeCoreJob},
        {"parseJob",      "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void *) ParseJob},
        {"getCommMap",    "()Ljava/lang/String;",                                     (void *) GetCommMap},
        {"getCoreMap",    "()Ljava/lang/String;",                                     (void *) GetCoreMap},

};

extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    jclass clz = env->FindClass("cn/yyxx/eyuancomm/base/SdkDrive");
    if (env->RegisterNatives(clz, gMethod, sizeof(gMethod) / sizeof(gMethod[0])) < 0) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

#ifdef __cplusplus
}
#endif