#!/bin/bash

COOLC=coolc
BUILD_DIR=build
TESTS_DIR=tests
TOTAL_TESTS=0
PASSED_TESTS=0
COOLC_SELF=$BUILD_DIR/cool

analyzer() {
    if [ "$#" -ne 2 ]; then
        echo "Usage: $0 <tests_dir> <exec_arg>"
        exit 1
    fi

    tests_dir=$TESTS_DIR/$1
    exec_arg=$2

    echo "Running tests for $1"

    passed=0
    for file_path in $(ls $tests_dir/*.cl); do
        ref_path=$tests_dir/$(basename $file_path .cl).ref

        file_name=$(basename $file_path)
        echo -en "Testing $file_name ... "

        ./$COOLC $exec_arg --module prelude $file_path 2>&1 | diff - $ref_path > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo -e "\e[32mPASSED\e[0m"
            passed=$((passed + 1))
        else
            echo -e "\e[31mFAILED\e[0m"
        fi
    done

    total=$(ls $tests_dir/*.cl | wc -l)
    echo "Passed $passed/$total tests"

    TOTAL_TESTS=$((TOTAL_TESTS + total))
    PASSED_TESTS=$((PASSED_TESTS + passed))
}

runner() {
    if [ "$#" -ne 2 ]; then
        echo "Usage: $0 <tests_dir> <exec_arg>"
        exit 1
    fi

    tests_dir=$TESTS_DIR/$1
    exec_arg=$2

    echo "Running tests for $1"

    passed=0
    for file_path in $(ls $tests_dir/*.cl); do
        ref_path=$tests_dir/$(basename $file_path .cl).ref

        file_name=$(basename $file_path .cl)
        echo -en "Testing $file_name.cl ... "

        ./$COOLC $exec_arg --module prelude $file_path 2>&1 > /tmp/$file_name.s 2>&1
        if [ $? -ne 0 ]; then
            echo -e "\e[31mFAILED\e[0m"
            continue
        fi

        fasm /tmp/$file_name.s 2>&1 > /dev/null
        if [ $? -ne 0 ]; then
            echo -e "\e[31mFAILED\e[0m"
            continue
        fi

        ld /tmp/$file_name.o -o /tmp/$file_name 2>&1 > /dev/null
        if [ $? -ne 0 ]; then
            echo -e "\e[31mFAILED\e[0m"
            continue
        fi

        /tmp/$file_name | diff - $ref_path > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo -e "\e[32mPASSED\e[0m"
            passed=$((passed + 1))
        else
            echo -e "\e[31mFAILED\e[0m"
        fi
    done

    total=$(ls $tests_dir/*.cl | wc -l)
    echo "Passed $passed/$total tests"

    TOTAL_TESTS=$((TOTAL_TESTS + total))
    PASSED_TESTS=$((PASSED_TESTS + passed))
}

librunner() {
    if [ "$#" -ne 1 ]; then
        echo "Usage: $0 <tests_dir>"
        exit 1
    fi

    tests_dir=$TESTS_DIR/$1
    exec_arg=$2

    echo "Running tests for $1"

    passed=0
    for file_path in $(ls $tests_dir/*.cl); do
        ref_path=$tests_dir/$(basename $file_path .cl).ref
        flags_path=$tests_dir/$(basename $file_path .cl).flags

        file_name=$(basename $file_path .cl)
        echo -en "Testing $file_name.cl ... "

        flags=$(cat $flags_path)

        ./$COOLC $flags $file_path 2>&1 -o /tmp/$file_name > /dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo -e "\e[31mFAILED\e[0m"
            continue
        fi

        /tmp/$file_name | diff - $ref_path > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo -e "\e[32mPASSED\e[0m"
            passed=$((passed + 1))
        else
            echo -e "\e[31mFAILED\e[0m"
        fi
    done

    total=$(ls $tests_dir/*.cl | wc -l)
    echo "Passed $passed/$total tests"

    TOTAL_TESTS=$((TOTAL_TESTS + total))
    PASSED_TESTS=$((PASSED_TESTS + passed))
}

self_hosted_lexical_analyzer() {
    echo "Testing the self hosted lexical analyzer"
    if [ "$#" -ne 1 ]; then
        echo "Usage: $0 <tests_dir>"
        exit 1
    fi

    tests_dir=$TESTS_DIR/$1

    echo "Running tests for $1"

    passed=0
    for file_path in $(ls $tests_dir/*.cl); do
        ref_path=$tests_dir/$(basename $file_path .cl).ref

        file_name=$(basename $file_path)
        echo -en "Testing $file_name ... "

        cat $file_path | ./$COOLC_SELF-lexer 2>&1 | diff - $ref_path > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo -e "\e[32mPASSED\e[0m"
            passed=$((passed + 1))
        else
            echo -e "\e[31mFAILED\e[0m"
        fi
    done

    total=$(ls $tests_dir/*.cl | wc -l)
    echo "Passed $passed/$total tests"

    TOTAL_TESTS=$((TOTAL_TESTS + total))
    PASSED_TESTS=$((PASSED_TESTS + passed))
}

self_hosted_parser_analyzer() {
    echo "Testing the self hosted parser analyzer"
    if [ "$#" -ne 1 ]; then
        echo "Usage: $0 <tests_dir>"
        exit 1
    fi

    tests_dir=$TESTS_DIR/$1

    echo "Running tests for $1"

    passed=0
    for file_path in $(ls $tests_dir/*.cl); do
        ref_path=$tests_dir/$(basename $file_path .cl).ref

        file_name=$(basename $file_path)
        echo -en "Testing $file_name ... "

        cat $file_path | ./$COOLC_SELF-parser 2>&1 | diff - $ref_path > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            echo -e "\e[32mPASSED\e[0m"
            passed=$((passed + 1))
        else
            echo -e "\e[31mFAILED\e[0m"
        fi
    done

    total=$(ls $tests_dir/*.cl | wc -l)
    echo "Passed $passed/$total tests"

    TOTAL_TESTS=$((TOTAL_TESTS + total))
    PASSED_TESTS=$((PASSED_TESTS + passed))
}

lexical_analyzer() {
    echo "Testing the lexical analyzer"
    analyzer lexer --lex
}

syntax_analyzer() {
    echo "Testing the syntax analyzer"
    analyzer parser --syn
    # self_hosted_parser_analyzer parser
}

semantic_analyzer() {
    echo "Testing the semantic analyzer"
    analyzer semantic --sem
    analyzer semantic2 --sem
}

tac_generator() {
    echo "Testing the TAC generator"
    analyzer tac --tac
}

asm_generator() {
    echo "Testing the assembly generator"
    runner asm --asm
}

lib_tests() {
    echo "Testing the lib tests"
    librunner lib
}

make clean && make

ARG1=$1
if [ "$ARG1" == "--lex" ]; then
    lexical_analyzer
elif [ "$ARG1" == "--syn" ]; then
    syntax_analyzer
elif [ "$ARG1" == "--sem" ]; then
    semantic_analyzer
elif [ "$ARG1" == "--tac" ]; then
    tac_generator
elif [ "$ARG1" == "--asm" ]; then
    asm_generator
elif [ "$ARG1" == "--lib" ]; then
    lib_tests
elif [ -z "$ARG1" ]; then
    lexical_analyzer
    syntax_analyzer
    semantic_analyzer
    tac_generator
    asm_generator
    lib_tests
else
    echo "Usage: $0 [--lex | --syn | --sem | --tac | --asm | --lib]"
    exit 1
fi

if [ $PASSED_TESTS -eq $TOTAL_TESTS ]; then
    echo -e "\e[32mAll tests passed\e[0m"
    exit 0
else
    echo -e "\e[31mSome tests failed\e[0m"
    exit 1
fi
