#include "../Tests.hpp"
#include "core/Frustum.hpp"
#include "core/Test.hpp"

#define R60 Core::degreeToRadian(60.0f)

using V3 = Core::Vector3;

static void testPointIsInside() {
    Core::IntVector2 size(200, 100);
    Core::Frustum f(R60, 0.1f, 1000.0f);
    f.updatePlanes(V3(0, 0, 0), V3(1, 0, 0), V3(0, 1, 0), V3(0, 0, 1), size);

    TEST_TRUE(f.isInside(V3(0.0f, 0.0f, 5.0f)));
    TEST_FALSE(f.isInside(V3(0.0f, 0.0f, 1004.0f)));
    TEST_FALSE(f.isInside(V3(0.0f, 0.0f, -5.0f)));
    TEST_FALSE(f.isInside(V3(0.0f, 50.0f, 5.0f)));
    TEST_FALSE(f.isInside(V3(0.0f, -50.0f, 5.0f)));
    TEST_FALSE(f.isInside(V3(50.0f, 0.0f, 5.0f)));
    TEST_FALSE(f.isInside(V3(-50.0f, 0.0f, 5.0f)));
}

static void testSphereIsInside() {
    Core::IntVector2 size(200, 100);
    Core::Frustum f(R60, 0.1f, 1000.0f);
    f.updatePlanes(V3(0, 0, 0), V3(1, 0, 0), V3(0, 1, 0), V3(0, 0, 1), size);

    TEST_TRUE(f.isInside(V3(0.0f, 0.0f, 5.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(0.0f, 0.0f, 1004.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(0.0f, 0.0f, -5.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(0.0f, 50.0f, 5.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(0.0f, -50.0f, 5.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(50.0f, 0.0f, 5.0f), 3.0f));
    TEST_FALSE(f.isInside(V3(-50.0f, 0.0f, 5.0f), 3.0f));

    TEST_TRUE(f.isInside(V3(0.0f, 0.0f, 5.0f), 3.0f));
    TEST_TRUE(f.isInside(V3(0.0f, 0.0f, 1004.0f), 50.0f));
    TEST_TRUE(f.isInside(V3(0.0f, 0.0f, -5.0f), 50.0f));
    TEST_TRUE(f.isInside(V3(0.0f, 50.0f, 5.0f), 50.0f));
    TEST_TRUE(f.isInside(V3(0.0f, -50.0f, 5.0f), 50.0f));
    TEST_TRUE(f.isInside(V3(50.0f, 0.0f, 5.0f), 50.0f));
    TEST_TRUE(f.isInside(V3(-50.0f, 0.0f, 5.0f), 50.0f));
}

static void testUpdateProjection() {
    Core::Frustum f(R60, 0.1f, 1000.0f);
    TEST_STRING(
        "[[1.30, 0.00, 0.00, 0.00], "
        "[0.00, 1.73, 0.00, 0.00], "
        "[0.00, 0.00, -1.00, -0.20], "
        "[0.00, 0.00, -1.00, 0.00]]",
        f.updateProjection(Core::IntVector2(400, 300)));
}

void testFrustum() {
    testPointIsInside();
    testSphereIsInside();
    testUpdateProjection();
}