#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h> // for EXIT_FAILURE
/*#include <int_list.h>*/

#include <int_stack.h>
/*#include <stack.h>*/

/*
 * test program for the stack implementation in stack.h.
 *
 * Author: Marc Meunier (mame0264@student.umu.se).
 *
 * Version information:
 *   2025-04-22: v1.0.  First version.
 */

#define VERSION "v1.0"
#define VERSION_DATE "2025-04-22"

/*
 * Function to compare the values stored in the list.
 */
bool value_equal(int v1, int v2)
{
    return v1 == v2;
}

// test that the stack_empty() function creates an empty stack.

void isempty_return_true(void)
{
    // print start message
    fprintf(stderr, "Starting isempty_return_true()...\n");
    // initialize stack
    stack s = stack_empty();
    // prints if function returns false
    if (!stack_is_empty(s))
    {
        fprintf(stderr, "\nStack is empty but \"stack_is_empty\" reports non empty\n");
    }

    // adds values to stack
    s = stack_push(s, 10);
    // test if stack prints false with values inside
    if (stack_is_empty(s))
    {
        fprintf(stderr, "\nStack is non empty but \"stack_is_empty\" reports empty.\n");
        
    }
    // print success message
    fprintf(stderr, "done.\n");
}

// tests if stack returns top value in stack. 
void push_stack_on_top(void)
{
    // startmessage
    fprintf(stderr, "Starting push_stack_on_top()...\n");
    // initialize stack
    stack s = stack_empty();

    
    // continues test where adding values to stack in a loop 
    for (int i = 1; i <= 10; i++)
    {
        s = stack_push(s, i);
    }

    int a = 0;
    // tests if values are returned in correct order when more values are in stack. 
    for (int i = 0; i <= 9; i++)
    {
        a = 10 - i;
        // check if value is same as the top value in stack and print message on error
        if (!value_equal(stack_top(s), a))
        {
            fprintf(stderr, "FAIL: Expected <%d>, got <%d>.\n", a, stack_top(s));
        }
        // removes one value from the stack to continue loop
        s = stack_pop(s);
    }
    // print function sucess message
    fprintf(stderr, "done.\n");
}
// tests if the top reads wrong value. 
void top_read_wrong(void)
{
    // start message
    fprintf(stderr, "Starting top_read_wrong()...\n");
    // initialize stack
    stack s = stack_empty();
    // loops over values to add to the stack.
    for (int i = 0; i <= 3; i++)
    {
        // adds value to stack
        s = stack_push(s,i);
        // check if value is not same as inserted value and prinnt error message
        if (stack_top(s) != i)
        {
            fprintf(stderr, "FAIL: Expected <%d>, got <%d>.\n", i, stack_top(s));
            exit(1);
        }
    }
    // function sucess message 
    fprintf(stderr,"done.\n");
}
// test if pop function removes the wrong value or works. 
void pop_remove_wrong(void)
{
    // startmessage
    fprintf(stderr, "Starting pop_remove_wrong()...\n");
    // stack iterations
    int iter = 3;
    // initialize stack
    stack s = stack_empty();
    // adds values to stack
    for (int i = 0; i <= iter; i++)
    {
        s = stack_push(s,i);
    }
    // check if values are correct 
    for (int i = 0; i <= iter; i++)
    {   
        if (!value_equal(stack_top(s), 3-i))
        {
            fprintf(stderr, "FAIL: Expected <%d>, got <%d>.\n", i, stack_top(s));
        }
        // removes top value from stack to check if it removes wrong later in loop. 
        s = stack_pop(s);
    }
    // end message
    fprintf(stderr,"done.\n");
} 


// main function to run the tests-
int main(void)
{
    // prinit start message
    printf("%s, %s %s: Test program for the typed int_stack datatype.\n",
           __FILE__, VERSION, VERSION_DATE);
    // function stack_empty();
    isempty_return_true();
    // function stack_push();
    push_stack_on_top();
    // function stack_top();
    top_read_wrong();
    // function stack_pop();
    pop_remove_wrong();
    // if everything sucessful print sucess message. 
    fprintf(stderr, "\nSUCCESS: Implementation passed all tests. Normal exit.\n");
    // exit without error. 
    return 0;
}
