#include "unity.h"
#include "CanDataHandler.h"

#define MAX_MESSAGE_SLOTS 100
#define MAX_EVENT_SLOTS 100


uint32_t hfdcan1 =0;

// Test when you register a new canid, it should return true.
void test_CanDataRegDataMsg_insert_valid() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    bool result = CanData_regDataMsg(canid);
    TEST_ASSERT_TRUE(result); // Check that the function returned true
}

// Test when you register a canid when all slots are filled, it should return false.
void test_CanDataRegDataMsg_insert_full() {
    CanDataHandler_reset(); // Reset the state of the module

    // Fill all the slots
    for (int i = 1; i < MAX_MESSAGE_SLOTS+1; i++) {
        bool result =  CanData_regDataMsg(i);
        TEST_ASSERT_TRUE(result);
    }

    // Try to register a new canid
    CanDataId canid = MAX_MESSAGE_SLOTS + 2; // This canid should not fit in the slots
    bool result = CanData_regDataMsg(canid);
    TEST_ASSERT_FALSE(result); // Check that the function returned false
}


// Test when registering the same canid multible times there should be no error 
void test_CanDataRegDataMsg_insert_duplicate() {
    CanDataHandler_reset(); // Reset the state of the module

    CanDataId canid = 1; // Test with a valid canid

    // Register the same canid multiple times
    for (int i = 0; i < 5; i++) {
        bool result = CanData_regDataMsg(canid);
        TEST_ASSERT_TRUE(result); // Check that the function returned true each time
    }
}


// A dummy event callback function for testing
void dummyEventCallback(CanDataId canid, uint8_t* data, uint8_t len) {
    // This function doesn't need to do anything
}

// Test when you register a new event callback, it should return true.
void test_CanDataRegEventMsg_insert_valid() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    bool result = CanData_regEventMsg(canid, dummyEventCallback);
    TEST_ASSERT_TRUE(result); // Check that the function returned true
}

// Test when you register an event callback when all slots are filled, it should return false.
void test_CanDataRegEventMsg_insert_full() {
    CanDataHandler_reset(); // Reset the state of the module

    // Fill all the slots
    for (int i = 1; i < MAX_EVENT_SLOTS+1; i++) {
        bool result =  CanData_regEventMsg(i, dummyEventCallback);
        TEST_ASSERT_TRUE(result); // Check that the function returned true
    }

    // Try to register a new event callback
    CanDataId canid = MAX_EVENT_SLOTS + 2; // This canid should not fit in the slots
    bool result = CanData_regEventMsg(canid, dummyEventCallback);
    TEST_ASSERT_FALSE(result); // Check that the function returned false
}

// Test when you register a canid with a NULL callback, it should return false.
void test_CanDataRegEventMsg_NullCallback() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    bool result = CanData_regEventMsg(canid, NULL);
    TEST_ASSERT_FALSE(result); // Check that the function returned false
}


// Test when you register a canid that has already been registered, it should return false.
void test_CanDataRegEventMsg_insert_duplicate() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid

    // Register the canid once
    bool result = CanData_regEventMsg(canid, dummyEventCallback);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Try to register the same canid again
    result = CanData_regEventMsg(canid, dummyEventCallback);
    TEST_ASSERT_FALSE(result); // Check that the function returned false
}


// Test for CanData_canFifo0RxCallback(CanDataId canid, uint8_t* data, uint8_t len) function
void test_CanData_canFifo0RxCallback_data_valid() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // Test with valid data
    uint8_t len = 8; // Test with a valid length

    // Register the canid
    bool result = CanData_regDataMsg(canid);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Call the function with the test parameters
    CanData_canFifo0RxCallback(canid, data, len);

    // Get the message that was processed
    const CanDataMessage* message = CanData_getDataMessage(canid);

    // Check that the message was processed correctly
    TEST_ASSERT_EQUAL_UINT8(len, message->data_length);
    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, message->data, len);
}

// Test for CanData_canFifo0RxCallback(CanDataId canid, uint8_t* data, uint8_t len) function
// Test with an invalid canid or NULL data, the function should handle the error correctly.
void test_CanData_canFifo0RxCallback_data_invalid() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    uint8_t* data = NULL; // Test with NULL data
    uint8_t len = 8; // Test with a valid length

    // Register the canid
    bool result = CanData_regDataMsg(canid);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Call the function with the test parameters
    CanData_canFifo0RxCallback(canid, data, len);

    // Get the message that was processed
    const CanDataMessage* message = CanData_getDataMessage(canid);

    // Check that the message was not processed
    TEST_ASSERT_EQUAL_UINT8(0, message->data_length);
}


bool test_CanData_canFifo1RxCallback_callbackCalled = false;

void test_CanData_canFifo1RxCallback_callback(CanDataId canid, uint8_t* data, uint8_t len) {
    test_CanData_canFifo1RxCallback_callbackCalled = true;
    TEST_ASSERT_EQUAL_UINT16(1,canid);
    TEST_ASSERT_EQUAL_UINT8(8,len);
}
// Test for CanData_canFifo1RxCallback(CanDataId canid, uint8_t* data, uint8_t len) function
void test_CanData_canFifo1RxCallback_data_valid() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid
    uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // Test with valid data
    uint8_t len = 8; // Test with a valid length

    // Register the canid with the callback
    bool result = CanData_regEventMsg(canid, test_CanData_canFifo1RxCallback_callback);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Call the function with the test parameters
    CanData_canFifo1RxCallback(canid, data, len);

    // Check that the callback was called
    TEST_ASSERT_TRUE(test_CanData_canFifo1RxCallback_callbackCalled);
}



bool test_CanData_removeEvent_callbackCalled = false;

void test_CanData_removeEvent_callback(CanDataId canid, uint8_t* data, uint8_t len) {
    test_CanData_removeEvent_callbackCalled = true;
    TEST_ASSERT_EQUAL_UINT16(1,canid);
    TEST_ASSERT_EQUAL_UINT8(8,len);
}

// Test for CanData_removeEvent(CanDataId canid) function
void test_CanData_removeEvent() {
    CanDataHandler_reset(); // Reset the state of the module
    CanDataId canid = 1; // Test with a valid canid

    // Register the canid with the callback
    bool result = CanData_regEventMsg(canid, test_CanData_removeEvent_callback);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Remove the canid
    result = CanData_removeEvent(canid);
    TEST_ASSERT_TRUE(result); // Check that the function returned true

    // Call the function with the test parameters
    uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // Test with valid data
    uint8_t len = 8; // Test with a valid length
    CanData_canFifo1RxCallback(canid, data, len);

    // Check that the callback was not called
    TEST_ASSERT_FALSE(test_CanData_removeEvent_callbackCalled);
}


void test_CanData_regDataManualMsg(void) {
    CanDataHandler_reset(); // Reset the state of the module

    {
        CanDataId canids[] = {1, 2, 3};
        size_t id_count = sizeof(canids) / sizeof(canids[0]);
        CLS_BSP_CAN_UniversalFilter filter = {
            .filterDestination = CLS_CAN_FILTER_TO_RXFIFO0,
            .filterMode = 0xff,
            .id0 = 0x7ff,
            .id1 = 0x003,
        };

        size_t result = CanData_regDataManualMsg(canids, id_count, &filter);
        TEST_ASSERT_EQUAL(id_count, result);

    }

    {
        CanDataId canids[] = {4, 5, 7};
        size_t id_count = sizeof(canids) / sizeof(canids[0]);
        CLS_BSP_CAN_UniversalFilter filter = {
            .filterDestination = CLS_CAN_FILTER_TO_RXFIFO0, 
            .filterMode = 0xf8,
            .id0 = 0x777,
            .id1 = 0x073,
        };

        size_t result = CanData_regDataManualMsg(canids, id_count, &filter);

        TEST_ASSERT_EQUAL(id_count, result);
    }
}



// Create a test runner function
void test_CanData(void) {
    RUN_TEST(test_CanDataRegDataMsg_insert_valid);
    RUN_TEST(test_CanDataRegDataMsg_insert_full);    
    RUN_TEST(test_CanDataRegDataMsg_insert_duplicate);
    RUN_TEST(test_CanDataRegEventMsg_insert_valid);    
    RUN_TEST(test_CanDataRegEventMsg_insert_full);
    RUN_TEST(test_CanDataRegEventMsg_NullCallback);    
    RUN_TEST(test_CanDataRegEventMsg_insert_duplicate);
    RUN_TEST(test_CanData_canFifo0RxCallback_data_valid);    
    RUN_TEST(test_CanData_canFifo0RxCallback_data_invalid);
    RUN_TEST(test_CanData_canFifo1RxCallback_data_valid);
    RUN_TEST(test_CanData_removeEvent);
    RUN_TEST(test_CanData_regDataManualMsg);
}
