//
// Created by #Suyghur, on 2021/10/15.
//

#include <jni.h>
#include "external/md5/md5.h"
#include "include/tool_kit.h"
#include "include/aes_kit.h"
#include "include/comm_map.h"
#include "include/yylog.h"
#include "include/params_kit.h"

#define API_KEY "qDikI9v?>!x)1rS&yo"

#ifdef __cplusplus
extern "C" {
#endif

void InitSdkDrive(JNIEnv *env, jobject clz, jobject context) {
    CommMap::GetInstance()->Init(env, context);
}


void SetParam(JNIEnv *env, jobject clz, jstring key, jstring value) {
    const char *_key = env->GetStringUTFChars(key, JNI_FALSE);
    const char *_value = env->GetStringUTFChars(value, JNI_FALSE);
    CommMap::GetInstance()->comm_params[_key] = _value;
    if (_key) {
        env->ReleaseStringUTFChars(key, _key);
    }
    if (_value) {
        env->ReleaseStringUTFChars(key, _value);
    }
}

jstring GetParam(JNIEnv *env, jobject clz, jstring key) {
    const char *_key = env->GetStringUTFChars(key, JNI_FALSE);
    const char *value = CommMap::GetInstance()->comm_params[_key].asCString();
    if (_key) {
        env->ReleaseStringUTFChars(key, value);
    }
    return env->NewStringUTF(value);
}

jstring InvokeJob(JNIEnv *env, jobject clz, jstring data) {
    const char *_data = env->GetStringUTFChars(data, JNI_FALSE);
    time_t t;
    long ts = time(&t);
    // 添加公共参数
    Json::Value root = ToolKit::ToJsonObject(_data);
    Json::Value::Members members = CommMap::GetInstance()->comm_params.getMemberNames();
    for (auto &member:members) {
        root[member] = CommMap::GetInstance()->comm_params[member];
    }
    // 加入时间戳
    std::string timestamp = std::to_string(ts);
    std::string sort_signature = ToolKit::GetJsonSortSignature(root);

    // time不参与排序，放到签名串最后一个
    sort_signature.append("&time=").append(timestamp).append(API_KEY);

    YYLog::D(env, "before md5: " + sort_signature);
    std::string sign = md5(sort_signature);

    root["time"] = timestamp;
    root["sign"] = sign;

    std::string random_str = ToolKit::GenerateRandString(5);
    std::string request_data = random_str.append(ToolKit::ToJsonString(root));
    jstring result = AesKit::Encrypt(env, request_data.c_str());

    YYLog::D(env, "请求路由: " + root["route_path"].asString());
    YYLog::D(env, "请求参数: " + request_data);

    YYLog::LogHandler(env, "请求路由: " + root["route_path"].asString() + "\n");
    YYLog::LogHandler(env, "请求参数: " + request_data + "\n");

    if (_data) {
        env->ReleaseStringUTFChars(data, _data);
    }
    return result;
}

jstring ParseJob(JNIEnv *env, jobject clz, jstring data) {
    const char *_data = env->GetStringUTFChars(data, JNI_FALSE);
    jstring result = AesKit::Decrypt(env, _data);
    if (_data) {
        env->ReleaseStringUTFChars(data, _data);
    }
    return result;
}

jstring RsaEncrypt(JNIEnv *env, jobject clz, jstring data) {
    const char *_data = env->GetStringUTFChars(data, JNI_FALSE);
    jstring result = ToolKit::RsaEncrypt(env, _data);
    if (_data) {
        env->ReleaseStringUTFChars(data, _data);
    }
    return result;
}

static JNINativeMethod gMethods[] = {
        {"initDrive",  "(Landroid/content/Context;)V",            (void *) InitSdkDrive},
        {"setParam",   "(Ljava/lang/String;Ljava/lang/String;)V", (void *) SetParam},
        {"getParam",   "(Ljava/lang/String;)Ljava/lang/String;",  (void *) GetParam},
        {"invokeJob",  "(Ljava/lang/String;)Ljava/lang/String;",  (void *) InvokeJob},
        {"parseJob",   "(Ljava/lang/String;)Ljava/lang/String;",  (void *) ParseJob},
        {"RsaEncrypt", "(Ljava/lang/String;)Ljava/lang/String;",  (void *) RsaEncrypt}
};

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("com/yyrh/core/SDKDrive");
    if (env->RegisterNatives(clz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

#ifdef __cplusplus
}
#endif


