#ifdef TESTS_BUILD
#include <stdint.h>
#include <vector>
#include "../extern/doctest.hpp"
#include "../src/Enum.hpp"
#include "../src/MacroUtils.hpp"

ENUM(TestEnum, uint8_t, Val1, Val2, Val3)

#define STATIC_REQUIRE(expr)                                                                                           \
    static_assert(expr);                                                                                               \
    REQUIRE(expr);

TEST_CASE("Parse Enum case sensitive") {
    STATIC_REQUIRE(TestEnumHelper::Parse("Val1") == TestEnum::Val1);
    STATIC_REQUIRE(TestEnumHelper::Parse("Val2") == TestEnum::Val2);
    STATIC_REQUIRE(TestEnumHelper::Parse("Val3") == TestEnum::Val3);
    CHECK_THROWS(TestEnumHelper::Parse("Val4"));
    CHECK_THROWS(TestEnumHelper::Parse("val1"));
}

TEST_CASE("Try Parse Enum case sensitive") {
    TestEnum v = static_cast<TestEnum>(255);
    REQUIRE(TestEnumHelper::TryParse("Val1", v));
    CHECK(v == TestEnum::Val1);
    REQUIRE(TestEnumHelper::TryParse("Val2", v));
    CHECK(v == TestEnum::Val2);
    REQUIRE(TestEnumHelper::TryParse("Val3", v));
    CHECK(v == TestEnum::Val3);
    CHECK_FALSE(TestEnumHelper::TryParse("Val4", v));
    CHECK_FALSE(TestEnumHelper::TryParse("val1", v));
}

TEST_CASE("Parse Enum case insensitive") {
    CHECK(TestEnumHelper::Parse("Val1", true) == TestEnum::Val1);
    CHECK(TestEnumHelper::Parse("Val2", true) == TestEnum::Val2);
    CHECK(TestEnumHelper::Parse("Val3", true) == TestEnum::Val3);
    CHECK(TestEnumHelper::Parse("val1", true) == TestEnum::Val1);
    CHECK(TestEnumHelper::Parse("vAL2", true) == TestEnum::Val2);
    CHECK(TestEnumHelper::Parse("VaL3", true) == TestEnum::Val3);
    CHECK_THROWS(TestEnumHelper::Parse("Val4", true));
}

TEST_CASE("Try Parse Enum case insensitive") {
    TestEnum v = static_cast<TestEnum>(255);
    REQUIRE(TestEnumHelper::TryParse("Val1", v, true));
    CHECK(v == TestEnum::Val1);
    REQUIRE(TestEnumHelper::TryParse("Val2", v, true));
    CHECK(v == TestEnum::Val2);
    REQUIRE(TestEnumHelper::TryParse("Val3", v, true));
    CHECK(v == TestEnum::Val3);
    REQUIRE(TestEnumHelper::TryParse("val1", v, true));
    CHECK(v == TestEnum::Val1);
    REQUIRE(TestEnumHelper::TryParse("vAL2", v, true));
    CHECK(v == TestEnum::Val2);
    REQUIRE(TestEnumHelper::TryParse("VaL3", v, true));
    CHECK(v == TestEnum::Val3);
    CHECK_FALSE(TestEnumHelper::TryParse("Val4", v, true));
}

TEST_CASE("Enum To String") {
    STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val1) == "Val1");
    STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val2) == "Val2");
    STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val3) == "Val3");

    CHECK(TestEnumHelper::ToString((TestEnum)100) == "out of bounds");
}

TEST_CASE("Enum Get Values") {
    auto vec = TestEnumHelper::GetValues();
    REQUIRE(vec.size() == 3);
    CHECK(vec[0] == TestEnum::Val1);
    CHECK(vec[1] == TestEnum::Val2);
    CHECK(vec[2] == TestEnum::Val3);
}

TEST_CASE("Enum Get Highest") { STATIC_REQUIRE(TestEnumHelper::Highest() == TestEnum::Val3); }

TEST_CASE("Enum Get Lowest") { STATIC_REQUIRE(TestEnumHelper::Lowest() == TestEnum::Val1); }

TEST_CASE("Enum Get First") { STATIC_REQUIRE(TestEnumHelper::First() == TestEnum::Val1); }

TEST_CASE("Enum Get Last") { STATIC_REQUIRE(TestEnumHelper::Last() == TestEnum::Val3); }

#endif