#include "gridcore/json.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>

// Tests the asset_1.json taht should be loaded by the rust caller
extern bool
start_test(GCJsonCallbacks json_callbacks)
{
    GCResultCallback result = GC_JSON_ERROR;
    GCJsonObject root = json_callbacks->data;
    assert(root.type == GC_JSON_TYPE_OBJECT && "Root is not an object");

    // Tests retrieving the value of the field "ethernet_interface"
    GCJsonObject ethernet_acess_value = json_callbacks->getObjectField(root, "ethernet_interface", &result);
    assert(result == GC_JSON_OK && "Failed to get ethernet_interface field");
    assert(ethernet_acess_value.type == GC_JSON_TYPE_STRING && "ethernet_interface is not an string");
    const char* ethernet_acess = json_callbacks->getString(ethernet_acess_value, &result);
    assert(result == GC_JSON_OK && "Failed to get ethernet_interface value");
    assert(strcmp(ethernet_acess, "eth0") == 0 && "ethernet_interface value is not eth0");
    json_callbacks->freeString((void*)ethernet_acess); // This is wrong, a callback must be called to
                                                       // free the string

    // Test retrieving non existent object field
    GCJsonObject non_existent_field = json_callbacks->getObjectField(root, "non-existent-field", &result);
    assert(result == GC_JSON_ERROR && "Failed to get non-existent-field field");

    // Tests retrieving the list of smv_subscribers
    GCJsonObject smv_subscribers = json_callbacks->getObjectField(root, "smv_subscribers", &result);
    assert(result == GC_JSON_OK && "Failed to get smv_subscribers field");
    assert(smv_subscribers.type == GC_JSON_TYPE_ARRAY && "smv_subscribers is not an array");
    int64_t smv_subscribers_length = json_callbacks->getArrayLength(smv_subscribers, &result);
    assert(result == GC_JSON_OK && "Failed to get smv_subscribers length");
    assert(smv_subscribers_length == 1 && "smv_subscribers length is not 1");

    // Test retrieving non existent array index
    GCJsonObject non_existent_array_idx = json_callbacks->getArrayIdx(smv_subscribers, 1, &result);
    assert(result == GC_JSON_ERROR && "Failed to get non-existent array index");

    // Tests retrieving the first element of the smv_subscribers list
    GCJsonObject first_smv_subscriber = json_callbacks->getArrayIdx(smv_subscribers, 0, &result);
    assert(result == GC_JSON_OK && "Failed to get first smv-subscriber");
    assert(first_smv_subscriber.type == GC_JSON_TYPE_OBJECT && "first smv-subscriber is not an object");

    // Tests retrieving the value of the field "app_id"
    GCJsonObject app_id_value = json_callbacks->getObjectField(first_smv_subscriber, "app_id", &result);
    assert(result == GC_JSON_OK && "Failed to get app_id field");
    assert(app_id_value.type == GC_JSON_TYPE_INT && "app_id is not an int");
    int64_t app_id = json_callbacks->getInt(app_id_value, &result);
    assert(result == GC_JSON_OK && "Failed to get app_id integer value");
    assert(app_id == 4001 && "app_id value is not 4001");

    // Test retrieving wrong data type
    json_callbacks->getInt(first_smv_subscriber, &result);
    assert(result == GC_JSON_ERROR && "Result is an object instead of an int");
    json_callbacks->getObjectField(first_smv_subscriber, "some_name", &result);
    assert(result == GC_JSON_ERROR && "Result is an object instead of an int");
    json_callbacks->getString(first_smv_subscriber, &result);
    assert(result == GC_JSON_ERROR && "Result is an object instead of a string");
    json_callbacks->getArrayIdx(first_smv_subscriber, 10, &result);
    assert(result == GC_JSON_ERROR && "Result is an object instead of an array");

    return 1;
}
