#include "blitz/misc/Test.h"

#include "blitz/maths/Physics.h"
#include "blitz/misc/Log.h"
#include "blitz/misc/Format.h"
#include <iostream>
#include <ostream>
#include <limits>

using namespace blitz;
using namespace maths;

#define let auto // sexy boiiii

static void test_left() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {-2.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_right() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {2.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_forward() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 2.0f, 0.0f}, {0.0f, -1.0f, 0.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_backward() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, -2.0f, 0.0f}, {0.0f, 1.0f, 0.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_above() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 0.0f, 2.0f}, {0.0f, 0.0f, -1.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_below() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 0.0f, -2.0f}, {0.0f, 0.0f, 1.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_shifted() {
    let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {-3.0f, 0.0f, 100.0f}, {1.0f, 0.0f, 0.0f} };

    blitz_test_assert(!Intersects(ray, box));
}

static void test_corner_inside() {
    let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 0.0f, 0.0f}, {0.5f, 0.5f, 0.5f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_corner_inside_weird() {
    let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_corner_inside_opposite_big() {
    let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.0f, 0.0f, 0.0f}, {1.5f, 1.5f, 1.5f} };

    blitz_test_assert(Intersects(ray, box));
}

static void test_corner_inside_opposite_weird() {
    let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
    let ray = Ray { {0.4f, 0.4f, 0.4f}, {-1.0f, -1.0f, -1.0f} };

    blitz_test_assert(Intersects(ray, box));
}

int main(int argc, const char* args[]) {
    test_left();
    test_right();
    test_forward();
    test_backward();
    test_below();
    test_above();
    test_shifted();
    test_corner_inside();
    test_corner_inside_weird();
    test_corner_inside_opposite_big();
    test_corner_inside_opposite_weird();
    return BLITZ_TEST_SUCCESSFUL;
}