#include "unity.h"
#include "bintree.h"
#include <stdlib.h>

static int compare(const void *a, const void *b)
{
    return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}

void setUp(void) { }
void tearDown(void) { }

void test_addToTree_single_element(void)
{
    TreeNode *root = NULL;
    int value = 10;
    int dup;

    root = addToTree(root, &value, sizeof(int), compare, &dup);

    TEST_ASSERT_NOT_NULL(root);
    TEST_ASSERT_EQUAL_INT(10, *(int*)root->data);
    TEST_ASSERT_EQUAL_INT(0, dup);    // neuer Eintrag

    clearTree(root);
}

void test_addToTree_multiple_elements_and_size(void)
{
    TreeNode *root = NULL;
    int values[] = {5, 3, 7, 1, 4};
    int dup;

    for (int i = 0; i < 5; i++)
        root = addToTree(root, &values[i], sizeof(int), compare, &dup);

    TEST_ASSERT_EQUAL_UINT(5, treeSize(root));

    clearTree(root);
}

void test_addToTree_duplicate_detection(void)
{
    TreeNode *root = NULL;
    int val = 42;
    int dup;

    root = addToTree(root, &val, sizeof(int), compare, &dup);
    TEST_ASSERT_EQUAL(0, dup);

    addToTree(root, &val, sizeof(int), compare, &dup);
    TEST_ASSERT_EQUAL(1, dup);

    clearTree(root);
}

void test_treeSize_empty_tree_detection(void)
{
    TEST_ASSERT_EQUAL_UINT(0, treeSize(NULL));
}

void test_nextTreeData_returns_inorder(void)
{
    TreeNode *root = NULL;
    int values[] = {5, 3, 7, 2, 4, 6, 8};

    // Einfügen
    for (int i = 0; i < 7; i++)
        root = addToTree(root, &values[i], sizeof(int), compare, NULL);

    /* Erwartete Reihenfolge (inorder): 2,3,4,5,6,7,8 */
    int expected[] = {2,3,4,5,6,7,8};

    int idx = 0;
    void *p = nextTreeData(root);   // Iterator starten

    while (p != NULL)
    {
        TEST_ASSERT_EQUAL_INT(expected[idx], *(int*)p);
        idx++;
        p = nextTreeData(NULL);     // Fortsetzen mit NULL
    }

    TEST_ASSERT_EQUAL(7, idx); //alle Einträge geprüft

    clearTree(root);
}

void test_treeSize_returns_correct_size()
{
    TreeNode *root = NULL;
    int values[] = {8, 3, 10, 1, 6, 14};

    //Baum aufbauen
    for (int i = 0; i < 6; i++)
        root = addToTree(root, &values[i], sizeof(int), compare, NULL);

    TEST_ASSERT_EQUAL_UINT(6, treeSize(root));

    // Baum löschen
    clearTree(root);
    root = NULL;

    TEST_ASSERT_EQUAL_UINT(0, treeSize(root));
}

int main(void)
{
    UNITY_BEGIN();
    
    printf("\n============================\n Bintree tests\n============================\n");

    RUN_TEST(test_addToTree_single_element);
    RUN_TEST(test_addToTree_multiple_elements_and_size);
    RUN_TEST(test_addToTree_duplicate_detection);
    RUN_TEST(test_treeSize_empty_tree_detection);
    RUN_TEST(test_nextTreeData_returns_inorder);
    RUN_TEST(test_treeSize_returns_correct_size);

    return UNITY_END();
}
