//
// Created by CORP\jingi.jung on 19. 5. 14.
//

#include <jni.h>
#include <string.h>
#include "../COMMON/bc_core/public/coldwallet_api.h"
#include "../COMMON/bc_core/public/msgs/coldwallet_msg.h"
#include "../COMMON/bc_core/shared/process_cmd.h"
#include "../COMMON/bc_core/public/coldwallet_errors.h"
#include "../COMMON/bc_core/shared/coldwallet_crypto_tl.h"
#include "tz_platform/vendor/Ndk/core/tl/VS_TZ_debug.h"
#include "../COMMON/tz_spay_common/public/spay_load_pin_random_msg.h"
#include <android/log.h>
#include <tl/TZ_Vendor_tl.h>
#include <process_cmd_private.h>
#include "../COMMON/tz_spay_common/public/spay_pin_random_util_tl.h"

void init() {
//    uint8_t rand_value[SPAY_RANDOM_NUMBER_SIZE] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14 };
//    set_pin_random(rand_value, SPAY_RANDOM_NUMBER_SIZE);
}


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR; // JNI version not supported.
    }
    TTY_LOG("bc-core-so loaded");
    init();
    return JNI_VERSION_1_6;
}

JNIEXPORT jobject JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_processCommand(JNIEnv *env, jclass type, jint cmdId, jbyteArray payload_, jint payloadLength) {

    jbyte *payload = (*env)->GetByteArrayElements(env, payload_, NULL);

    tciMessage_t sendTciMessage;
    tciMessage_t respTciMessage;

    memset(&sendTciMessage, 0x00, sizeof(sendTciMessage));
    memset(&respTciMessage, 0x00, sizeof(respTciMessage));

    TTY_LOG("CMD[%d] - payload length : %d",cmdId, payloadLength);
    TTY_LOG("Sizeof TciMessage : %ld", sizeof(sendTciMessage));

    if(sizeof(sendTciMessage) < payloadLength) {
        TTY_ERROR_LOG("payload length is larger than tciMessage %ld - %ld", sizeof(sendTciMessage), payloadLength);
    }

    memcpy(&sendTciMessage.payload, payload, (size_t)payloadLength);

    int32_t result;

    // handling commands in vendor codes.
    if (cmdId == CMD_SPAY_SETUP_PIN_RANDOM){
        TTY_LOG("Encapsulated pin random len = %d"
        , sendTciMessage.payload.setup_pin_random.payload.cmd.pin_random_so.len);
        IS_BUFFER_VALID(sizeof(sendTciMessage), tz_spay_setup_pin_random_cmd_t,
                        sizeof(respTciMessage), tz_spay_setup_pin_random_resp_t) {
            respTciMessage.payload.setup_pin_random.payload.resp.pin_random_so.len =
                    sizeof(respTciMessage.payload.setup_pin_random.payload.resp.pin_random_so.so);
            result = decapsulate_and_rewrap(
                    (uint8_t *)"pay_auth", sizeof("pay_auth"),
                    sendTciMessage.payload.setup_pin_random.payload.cmd.pin_random_so.so,
                    sendTciMessage.payload.setup_pin_random.payload.cmd.pin_random_so.len,
                    respTciMessage.payload.setup_pin_random.payload.resp.pin_random_so.so,
                    &respTciMessage.payload.setup_pin_random.payload.resp.pin_random_so.len);
            respTciMessage.payload.setup_pin_random.payload.resp.return_code = (uint32_t)result;
            respTciMessage.spayhdr.header.len = sizeof(tz_spay_setup_pin_random_resp_t);
        }
    } else if (cmdId == CMD_SPAY_LOAD_PIN_RANDOM) {
        TTY_LOG("pin random so len = %d",
                sendTciMessage.payload.load_pin_random.payload.cmd.pin_random_so.len);
        IS_BUFFER_VALID(sizeof(sendTciMessage), tz_spay_load_pin_random_cmd_t,
                        sizeof(respTciMessage), tz_spay_load_pin_random_resp_t) {
            result = unwrap_pin_random_so(sendTciMessage.payload.load_pin_random.payload.cmd.pin_random_so.len,
                                          sendTciMessage.payload.load_pin_random.payload.cmd.pin_random_so.so);
            respTciMessage.payload.load_pin_random.payload.resp.return_code = (uint32_t)result;
            respTciMessage.spayhdr.header.len = sizeof(tz_spay_load_pin_random_resp_t);
        }
    } else {
        result = process_cmd((uint32_t )cmdId
                , &sendTciMessage, sizeof(sendTciMessage)
                , &respTciMessage, sizeof(respTciMessage));
    }

    // only for NDK and Window Ver.
    clear_cnt_of_unwrap_session_data_for_vcTest();




    jbyteArray retVal = (*env)->NewByteArray(env, sizeof(respTciMessage.payload));
    (*env)->SetByteArrayRegion(env, retVal, 0, sizeof(respTciMessage.payload),
                               (const jbyte *) &respTciMessage.payload);

    jclass class = (*env)->FindClass(env,"com/samsung/android/blockchainnativelibs/response/TANativeResponse");

    jmethodID cid = (*env)->GetMethodID(env,class, "<init>", "()V");
    jobject newObject = (*env)->NewObject(env, class, cid, "()V");

    jfieldID fid = (*env)->GetFieldID(env, class, "result", "I");
    (*env)->SetIntField(env, newObject, fid, result);

    fid = (*env)->GetFieldID(env, class, "errorMessage", "Ljava/lang/String;");
    jstring errorMessage = (*env)->NewStringUTF(env, "");
    (*env)->SetObjectField(env, newObject, fid, errorMessage);

    fid = (*env)->GetFieldID(env, class, "payload", "[B");
    (*env)->SetObjectField(env, newObject, fid, retVal);

    (*env)->DeleteLocalRef(env, retVal);

    return newObject;
}

JNIEXPORT jint JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_setBtcTransaction(
        JNIEnv *env,
        jclass type,
        jbyteArray test_tx_info,
        jint test_tx_info_len) {

    TTY_LOG("test1");
    jbyte *test_tx_info_struct = (*env)->GetByteArrayElements(env, test_tx_info, NULL);
    in_utxo_data_t input;
    memcpy(&input, test_tx_info_struct, test_tx_info_len);
    TTY_LOG("test2");
    jint res = set_btc_transaction(&input);
    return res;
}

JNIEXPORT jint JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_setBtcPrevUtxo(
        JNIEnv *env,
        jclass type,
        jbyteArray test_prev_utxo,
        jint test_prev_utxo_len) {

    jbyte *input_ptr = (*env)->GetByteArrayElements(env, test_prev_utxo, NULL);

    tz_btc_set_prv_utxo_msg_payload_t *test_prev_utxo_struct = (jbyte*)input_ptr;
    tz_btc_set_prv_utxo_msg_payload_t test_prev_utxo_resp;

    if(test_prev_utxo_len != sizeof(tz_btc_set_prv_utxo_msg_payload_t))
        return JNI_ERR;

    jint res = set_btc_prev_utxo(test_prev_utxo_struct,&test_prev_utxo_resp);

    return res;
}

JNIEXPORT void JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_setNonce(
        JNIEnv *env,
        jclass type,
        jbyteArray test_nonce,
        jint test_nonce_len) {
    jbyte *test_nonce_ptr = (*env)->GetByteArrayElements(env, test_nonce, NULL);
    set_nonce(test_nonce_ptr, test_nonce_len);
}

JNIEXPORT void JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_setPinRandom(
        JNIEnv *env,
        jclass type,
        jbyteArray test_pin_random,
        jint test_pin_random_len) {
    jbyte *test_pin_random_ptr = (*env)->GetByteArrayElements(env, test_pin_random, NULL);
    set_pin_random((uint8_t *)test_pin_random_ptr, test_pin_random_len);
}

JNIEXPORT jint JNICALL
Java_com_samsung_android_blockchainnativelibs_BcTaNativeHandler_btcSign(
        JNIEnv *env,
        jclass type,
        jbyteArray test_input) {
    jbyte *test_input_ptr = (*env)->GetByteArrayElements(env, test_input, NULL);
    tz_btc_sign_msg_payload_t test_respmsg;
    jint res = btc_sign(test_input_ptr,&test_respmsg);
    return res;
}
