/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include <catch2/catch_all.hpp>

#include "Math/Math.hpp"
#include "Math/AABB.hpp"

using namespace OpenVulkano::Math;

TEST_CASE("Default Constructor", "[AABB]")
{
	AABB aabb;
	REQUIRE(aabb.GetMin() == Vector3f(INFINITY));
	REQUIRE(aabb.GetMax() == Vector3f(-INFINITY));
}

TEST_CASE("Constructor with min and max", "[AABB]")
{
	Vector3f min(1.0f, 2.0f, 3.0f);
	Vector3f max(4.0f, 5.0f, 6.0f);
	AABB aabb(min, max);
	REQUIRE(aabb.GetMin() == min);
	REQUIRE(aabb.GetMax() == max);
}

TEST_CASE("Constructor with single point", "[AABB]")
{
	Vector3f point(1.0f, 2.0f, 3.0f);
	AABB aabb(point);
	REQUIRE(aabb.GetMin() == point);
	REQUIRE(aabb.GetMax() == point);
}

TEST_CASE("Constructor with point and radius", "[AABB]")
{
	Vector3f point(1.0f, 2.0f, 3.0f);
	float radius = 1.0f;
	AABB aabb(point, radius);
	REQUIRE(aabb.GetMin() == (point - radius));
	REQUIRE(aabb.GetMax() == (point + radius));
}

TEST_CASE("Init with single point", "[AABB]")
{
	AABB aabb;
	Vector3f point(1.0f, 2.0f, 3.0f);
	aabb.Init(point);
	REQUIRE(aabb.GetMin() == point);
	REQUIRE(aabb.GetMax() == point);
}

TEST_CASE("Init with min and max", "[AABB]")
{
	AABB aabb;
	Vector3f min(1.0f, 2.0f, 3.0f);
	Vector3f max(4.0f, 5.0f, 6.0f);
	aabb.Init(min, max);
	REQUIRE(aabb.GetMin() == min);
	REQUIRE(aabb.GetMax() == max);
}

TEST_CASE("Init with point and radius", "[AABB]")
{
	AABB aabb;
	Vector3f point(1.0f, 2.0f, 3.0f);
	float radius = 1.0f;
	aabb.Init(point, radius);
	REQUIRE(aabb.GetMin() == (point - radius));
	REQUIRE(aabb.GetMax() == (point + radius));
}

TEST_CASE("Grow with point", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(1.0f));
	Vector3f point(2.0f, 3.0f, 4.0f);
	aabb.Grow(point);
	REQUIRE(aabb.GetMin() == Vector3f(0.0f, 0.0f, 0.0f));
	REQUIRE(aabb.GetMax() == point);
}

TEST_CASE("Grow with AABB", "[AABB]")
{
	AABB aabb1(Vector3f(0.0f), Vector3f(1.0f));
	AABB aabb2(Vector3f(-1.0f), Vector3f(2.0f));
	aabb1.Grow(aabb2);
	REQUIRE(aabb1.GetMin() == Vector3f(-1.0f));
	REQUIRE(aabb1.GetMax() == Vector3f(2.0f));
}

TEST_CASE("GetDiagonal", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(1.0f));
	REQUIRE(aabb.GetDiagonal() == Vector3f(1.0f));
}

TEST_CASE("GetCenter", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(2.0f));
	REQUIRE(aabb.GetCenter() == Vector3f(1.0f));
}

TEST_CASE("IsOverlapping", "[AABB]")
{
	AABB aabb1(Vector3f(0.0f), Vector3f(1.0f));
	AABB aabb2(Vector3f(0.5f), Vector3f(1.5f));
	REQUIRE(aabb1.IsOverlapping(aabb2));

	AABB aabb3(Vector3f(2.0f), Vector3f(3.0f));
	REQUIRE_FALSE(aabb1.IsOverlapping(aabb3));
}

TEST_CASE("InBounds", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(1.0f));

	REQUIRE(aabb.InBounds(Vector3f(0.5f)));
    REQUIRE(aabb.InBounds(Vector3f(0.0f)));
    REQUIRE(aabb.InBounds(Vector3f(1.0f)));

    REQUIRE_FALSE(aabb.InBounds(Vector3f(1.1f)));
    REQUIRE_FALSE(aabb.InBounds(Vector3f(-0.1f)));
	REQUIRE_FALSE(aabb.InBounds(Vector3f(2.0f)));
}

TEST_CASE("Inside", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(1.0f));

	REQUIRE(aabb.Inside(Vector3f(0.5f)));

    REQUIRE_FALSE(aabb.Inside(Vector3f(0.0f)));
    REQUIRE_FALSE(aabb.Inside(Vector3f(1.0f)));
    REQUIRE_FALSE(aabb.Inside(Vector3f(1.1f)));
    REQUIRE_FALSE(aabb.Inside(Vector3f(-0.1f)));
	REQUIRE_FALSE(aabb.Inside(Vector3f(1.0f)));
}

TEST_CASE("IsEmpty", "[AABB]")
{
	AABB aabb;
	REQUIRE(aabb.IsEmpty());

	aabb.Init(Vector3f(0.0f), Vector3f(1.0f));
	REQUIRE_FALSE(aabb.IsEmpty());
}

TEST_CASE("Reset", "[AABB]")
{
	AABB aabb(Vector3f(0.0f), Vector3f(1.0f));
	aabb.Reset();
	REQUIRE(aabb.IsEmpty());
}