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

using Q = Core::Quaternion;
using V3 = Core::Vector3;

static void testInit() {
    Q q;
    TEST_STRING("(0.000 i + 0.000 j + 0.000 k + 1.000)", q);
}

static void testAxisAndDegreesInit() {
    Q q(V3(1.0f, 2.0f, 3.0f), Core::degreeToRadian(142.0f));
    TEST_STRING("(0.253 i + 0.505 j + 0.758 k + 0.326)", q);
}

static void testLerp() {
    Q q1(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(130.0f));
    Q q2(V3(1.0f, 2.0f, 4.0f), Core::degreeToRadian(260.0f));
    Q q3 = q1.lerp(0.3f, q2);
    TEST_STRING("(0.223 i + 0.529 j + 0.810 k + 0.119)", q3);
}

static void testMulSet() {
    Q q1(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(50.0f));
    Q q2(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(60.0f));
    Q q3;
    q3 *= q1;
    TEST_STRING(q1, q3);
    q3 *= q2;
    TEST_STRING(Q(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(110.0f)), q3);
}

static void testMul() {
    Q q1(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(50.0f));
    Q q2(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(60.0f));
    Q q3;
    q3 = q1 * q2;
    TEST_STRING(Q(V3(2.0f, 5.0f, 7.0f), Core::degreeToRadian(110.0f)), q3);
}

static void testMulVector() {
    Q q1(V3(1.0f, 0.0f, 0.0f), Core::degreeToRadian(90.0f));
    Q q2(V3(0.0f, 1.0f, 0.0f), Core::degreeToRadian(90.0f));
    Q q3(V3(0.0f, 0.0f, 1.0f), Core::degreeToRadian(90.0f));

    V3 v1(1.0f, 0.0f, 0.0f);
    V3 v2(0.0f, 1.0f, 0.0f);
    V3 v3(0.0f, 0.0f, 1.0f);

    TEST(V3(1.0f, 0.0f, 0.0f), q1 * v1);
    TEST(V3(0.0f, 0.0f, 1.0f), q1 * v2);
    TEST(V3(0.0f, -1.0f, 0.0f), q1 * v3);
    TEST(V3(0.0f, 0.0f, -1.0f), q2 * v1);
    TEST(V3(0.0f, 1.0f, 0.0f), q2 * v2);
    TEST(V3(1.0f, 0.0f, 0.0f), q2 * v3);
    TEST(V3(0.0f, 1.0f, 0.0f), q3 * v1);
    TEST(V3(-1.0f, 0.0f, 0.0f), q3 * v2);
    TEST(V3(0.0f, 0.0f, 1.0f), q3 * v3);
}

void testQuaternion() {
    testInit();
    testAxisAndDegreesInit();
    testLerp();
    testMulSet();
    testMul();
    testMulVector();
}