// =====================================================================================================================
//  fennec-test, a program to execute unit tests for fennec
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================


#ifndef FENNEC_TEST_MATRIX_H
#define FENNEC_TEST_MATRIX_H

#include <fennec/math/detail/_forward.h>

#include <fennec/math/matrix.h>

#include <iostream>

namespace fennec::test
{

	inline void fennec_test_math_matrix()
	{
		fennec_test_section("component_count");

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<mat2x2>  == 4),  true);
		fennec_test_run((component_count_v<mat2x3>  == 6),  true);
		fennec_test_run((component_count_v<mat3x2>  == 6),  true);
		fennec_test_run((component_count_v<mat3x3>  == 9),  true);
		fennec_test_run((component_count_v<mat3x4>  == 12), true);
		fennec_test_run((component_count_v<mat4x3>  == 12), true);
		fennec_test_run((component_count_v<mat4x4>  == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<mat2x2&> == 4),  true);
		fennec_test_run((component_count_v<mat2x3&> == 6),  true);
		fennec_test_run((component_count_v<mat3x2&> == 6),  true);
		fennec_test_run((component_count_v<mat3x3&> == 9),  true);
		fennec_test_run((component_count_v<mat3x4&> == 12), true);
		fennec_test_run((component_count_v<mat4x3&> == 12), true);
		fennec_test_run((component_count_v<mat4x4&> == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<mat2x2&&> == 4),  true);
		fennec_test_run((component_count_v<mat2x3&&> == 6),  true);
		fennec_test_run((component_count_v<mat3x2&&> == 6),  true);
		fennec_test_run((component_count_v<mat3x3&&> == 9),  true);
		fennec_test_run((component_count_v<mat3x4&&> == 12), true);
		fennec_test_run((component_count_v<mat4x3&&> == 12), true);
		fennec_test_run((component_count_v<mat4x4&&> == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<const mat2x2&> == 4),  true);
		fennec_test_run((component_count_v<const mat2x3&> == 6),  true);
		fennec_test_run((component_count_v<const mat3x2&> == 6),  true);
		fennec_test_run((component_count_v<const mat3x3&> == 9),  true);
		fennec_test_run((component_count_v<const mat3x4&> == 12), true);
		fennec_test_run((component_count_v<const mat4x3&> == 12), true);
		fennec_test_run((component_count_v<const mat4x4&> == 16), true);

		fennec_test_spacer(2);

		fennec_test_run((component_count_v<dmat2x2>  == 4),  true);
		fennec_test_run((component_count_v<dmat2x3>  == 6),  true);
		fennec_test_run((component_count_v<dmat3x2>  == 6),  true);
		fennec_test_run((component_count_v<dmat3x3>  == 9),  true);
		fennec_test_run((component_count_v<dmat3x4>  == 12), true);
		fennec_test_run((component_count_v<dmat4x3>  == 12), true);
		fennec_test_run((component_count_v<dmat4x4>  == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<dmat2x2&> == 4),  true);
		fennec_test_run((component_count_v<dmat2x3&> == 6),  true);
		fennec_test_run((component_count_v<dmat3x2&> == 6),  true);
		fennec_test_run((component_count_v<dmat3x3&> == 9),  true);
		fennec_test_run((component_count_v<dmat3x4&> == 12), true);
		fennec_test_run((component_count_v<dmat4x3&> == 12), true);
		fennec_test_run((component_count_v<dmat4x4&> == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<dmat2x2&&> == 4),  true);
		fennec_test_run((component_count_v<dmat2x3&&> == 6),  true);
		fennec_test_run((component_count_v<dmat3x2&&> == 6),  true);
		fennec_test_run((component_count_v<dmat3x3&&> == 9),  true);
		fennec_test_run((component_count_v<dmat3x4&&> == 12), true);
		fennec_test_run((component_count_v<dmat4x3&&> == 12), true);
		fennec_test_run((component_count_v<dmat4x4&&> == 16), true);

		fennec_test_spacer(1);

		fennec_test_run((component_count_v<const dmat2x2&> == 4),  true);
		fennec_test_run((component_count_v<const dmat2x3&> == 6),  true);
		fennec_test_run((component_count_v<const dmat3x2&> == 6),  true);
		fennec_test_run((component_count_v<const dmat3x3&> == 9),  true);
		fennec_test_run((component_count_v<const dmat3x4&> == 12), true);
		fennec_test_run((component_count_v<const dmat4x3&> == 12), true);
		fennec_test_run((component_count_v<const dmat4x4&> == 16), true);

		fennec_test_spacer(2);



		fennec_test_section("matrix equality operators");

		fennec_test_spacer(1);

		fennec_test_run(mat2() == mat2(), true);
		fennec_test_run(mat3() == mat3(), true);
		fennec_test_run(mat4() == mat4(), true);

		fennec_test_spacer(1);

		fennec_test_run(mat2() != mat2(), false);
		fennec_test_run(mat3() != mat3(), false);
		fennec_test_run(mat4() != mat4(), false);

		fennec_test_spacer(2);



		fennec_test_section("matrix constructors");

		fennec_test_spacer(1);

		fennec_test_run(mat2(), mat2(0));
		fennec_test_run(mat3(), mat3(0));
		fennec_test_run(mat4(), mat4(0));

		fennec_test_spacer(1);

		fennec_test_run(mat2(1), mat2(1, 0, 0, 1));
		fennec_test_run(mat3(1), mat3(1, 0, 0, 0, 1, 0, 0, 0, 1));
		fennec_test_run(mat4(1), mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));

		fennec_test_spacer(2);



		fennec_test_section("matrix-scalar operators");

		fennec_test_spacer(1);

		fennec_test_run(mat2x2(1, 2, 3, 4)                * 2, mat2x2(2, 4, 6, 8));
		fennec_test_run(mat2x3(1, 2, 3, 4, 5, 6)          * 2, mat2x3(2, 4, 6, 8, 10, 12));
		fennec_test_run(mat3x2(1, 2, 3, 4, 5, 6)          * 2, mat3x2(2, 4, 6, 8, 10, 12));
		fennec_test_run(mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9) * 2, mat3x3(2, 4, 6, 8, 10, 12, 14, 16, 18));

		fennec_test_spacer(2);



		fennec_test_section("matrix-vector operators");

		fennec_test_spacer(1);

		fennec_test_run(vec2(1, 2) * mat2x2(1, 2, 3, 4), vec2(5, 11));
		fennec_test_run(vec2(1, 2) * mat3x2(1, 2, 3, 4, 5, 6), vec3(5, 11, 17));
		fennec_test_run(vec2(1, 2) * mat4x2(1, 2, 3, 4, 5, 6, 7, 8), vec4(5, 11, 17, 23));

		fennec_test_spacer(1);

		fennec_test_run(vec3(1, 2, 3) * mat2x3(1, 2, 3, 4, 5, 6),                      vec2(14, 32));
		fennec_test_run(vec3(1, 2, 3) * mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9),             vec3(14, 32, 50));
		fennec_test_run(vec3(1, 2, 3) * mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), vec4(14, 32, 50, 68));

		fennec_test_spacer(2);



		fennec_test_section("matrix-matrix operators");

		fennec_test_spacer(1);

		fennec_test_run(mat2x2(1, 2, 3, 4) * mat2x2(1, 2, 3, 4),             mat2x2(7, 10, 15, 22));
		fennec_test_run(mat2x2(1, 2, 3, 4) * mat3x2(1, 2, 3, 4, 5, 6),       mat3x2(7, 10, 15, 22, 23, 34));
		fennec_test_run(mat2x2(1, 2, 3, 4) * mat4x2(1, 2, 3, 4, 5, 6, 7, 8), mat4x2(7, 10, 15, 22, 23, 34, 31, 46));

		fennec_test_spacer(1);

		fennec_test_run(mat2x3(1, 2, 3, 4, 5, 6) * mat2x2(1, 2, 3, 4),             mat2x3(9, 12, 15, 19, 26, 33));
		fennec_test_run(mat2x3(1, 2, 3, 4, 5, 6) * mat3x2(1, 2, 3, 4, 5, 6),       mat3x3(9, 12, 15, 19, 26, 33, 29, 40, 51));
		fennec_test_run(mat2x3(1, 2, 3, 4, 5, 6) * mat4x2(1, 2, 3, 4, 5, 6, 7, 8), mat4x3(9, 12, 15, 19, 26, 33, 29, 40, 51, 39, 54, 69));

		fennec_test_spacer(1);

		fennec_test_run(mat3x2(1, 2, 3, 4, 5, 6) * mat2x3(1, 2, 3, 4, 5, 6),                      mat2x2(22, 28, 49, 64));
		fennec_test_run(mat3x2(1, 2, 3, 4, 5, 6) * mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9),             mat3x2(22, 28, 49, 64, 76, 100));
		fennec_test_run(mat3x2(1, 2, 3, 4, 5, 6) * mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), mat4x2(22, 28, 49, 64, 76, 100, 103, 136));

		fennec_test_spacer(1);

		fennec_test_run(mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9) * mat2x3(1, 2, 3, 4, 5, 6),                      mat2x3(30, 36, 42, 66, 81, 96));
		fennec_test_run(mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9) * mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9),             mat3x3(30, 36, 42, 66, 81, 96, 102, 126, 150));
		fennec_test_run(mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9) * mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), mat4x3(30, 36, 42, 66, 81, 96, 102, 126, 150, 138, 171, 204));

		fennec_test_spacer(1);

		fennec_test_run(mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat2x3(1, 2, 3, 4, 5, 6),                      mat2x4(38, 44, 50, 56, 83, 98, 113, 128));
		fennec_test_run(mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9),             mat3x4(38, 44, 50, 56, 83, 98, 113, 128, 128, 152, 176, 200));
		fennec_test_run(mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), mat4x4(38, 44, 50, 56, 83, 98, 113, 128, 128, 152, 176, 200, 173, 206, 239, 272));

		fennec_test_spacer(1);

		fennec_test_run(mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat2x4(1, 2, 3, 4, 5, 6, 7, 8),                                mat2x3(70, 80, 90, 158, 184, 210));
		fennec_test_run(mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),                 mat3x3(70, 80, 90, 158, 184, 210, 246, 288, 330));
		fennec_test_run(mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) * mat4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), mat4x3(70, 80, 90, 158, 184, 210, 246, 288, 330, 334, 392, 450));

		fennec_test_spacer(1);

		fennec_test_run(mat4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) * mat2x4(1, 2, 3, 4, 5, 6, 7, 8),                                mat2x4(90, 100, 110, 120, 202, 228, 254, 280));
		fennec_test_run(mat4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) * mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),                 mat3x4(90, 100, 110, 120, 202, 228, 254, 280, 314,356,398,440));
		fennec_test_run(mat4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) * mat4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), mat4x4(90, 100, 110, 120, 202, 228, 254, 280, 314, 356, 398, 440, 426, 484, 542, 600));

		fennec_test_spacer(2);



		fennec_test_section("matrixCompMult");

		fennec_test_spacer(1);

		fennec_test_run(fennec::matrixCompMult(mat2(1, 2, 3, 4),                                        mat2(1)), mat2(1, 0, 0, 4));
		fennec_test_run(fennec::matrixCompMult(mat3(1, 4, 8, 6, 2, 5, 9, 7, 3),                         mat3(1)), mat3(1, 0, 0, 0, 2, 0, 0, 0, 3));
		fennec_test_run(fennec::matrixCompMult(mat4(2, 1, -3, 4, -1, 0, 2, 5, 3, 2, 1, 0, 4, -2, 3, 1), mat4(1)), mat4(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));

		fennec_test_spacer(2);



		fennec_test_section("outerProduct");

		fennec_test_spacer(1);

		fennec_test_run(fennec::outerProduct(vec2(1, 2),       vec2(3, 4)),       mat2(3, 6, 4, 8));
		fennec_test_run(fennec::outerProduct(vec3(1, 2, 3),    vec3(4, 5, 6)),    mat3(4,  8, 12,  5, 10, 15,  6, 12, 18));
		fennec_test_run(fennec::outerProduct(vec4(1, 2, 3, 4), vec4(5, 6, 7, 8)), mat4(5, 10, 15, 20,  6, 12, 18, 24, 7, 14, 21, 28, 8, 16, 24, 32));

		fennec_test_spacer(1);

		fennec_test_run(fennec::outerProduct(vec3(1, 2, 3), vec2(4, 5)),    mat2x3(4, 8, 12, 5, 10, 15));
		fennec_test_run(fennec::outerProduct(vec2(1, 2),    vec3(3, 4, 5)), mat3x2(3, 6,  4, 8,  5, 10));

		fennec_test_spacer(1);

		fennec_test_run(fennec::outerProduct(vec4(1, 2, 3, 4), vec2(5, 6)),       mat2x4(5, 10, 15, 20, 6, 12, 18, 24));
		fennec_test_run(fennec::outerProduct(vec2(1, 2),       vec4(3, 4, 5, 6)), mat4x2(3,  6,  4,  8, 5, 10,  6, 12));

		fennec_test_spacer(1);

		fennec_test_run(fennec::outerProduct(vec4(1, 2, 3, 4), vec3(5, 6, 7)),    mat3x4(5, 10, 15, 20,  6, 12, 18, 24,  7, 14, 21, 28));
		fennec_test_run(fennec::outerProduct(vec3(1, 2, 3),    vec4(4, 5, 6, 7)), mat4x3(4,  8, 12,  5, 10, 15,  6, 12, 18,  7, 14, 21));

		fennec_test_spacer(2);



		fennec_test_section("transpose");

		fennec_test_spacer(1);

		fennec_test_run(fennec::transpose(mat2(1, 2, 3, 4)),                                            mat2(1, 3, 2, 4));
		fennec_test_run(fennec::transpose(mat3(1, 2, 3, 4, 5, 6, 7, 8, 9)),                             mat3(1, 4, 7,  2, 5, 8,  3,  6, 9));
		fennec_test_run(fennec::transpose(mat4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)), mat4(1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16));

		fennec_test_spacer(1);

		fennec_test_run(fennec::transpose(mat3x2(1, 2, 3, 4, 5, 6)), mat2x3(1, 3, 5, 2, 4, 6));
		fennec_test_run(fennec::transpose(mat2x3(1, 2, 3, 4, 5, 6)), mat3x2(1, 4, 2, 5, 3, 6));

		fennec_test_spacer(1);

		fennec_test_run(fennec::transpose(mat4x2(1, 2, 3, 4, 5, 6, 7, 8)), mat2x4(1, 3, 5, 7, 2, 4, 6, 8));
		fennec_test_run(fennec::transpose(mat2x4(1, 2, 3, 4, 5, 6, 7, 8)), mat4x2(1, 5, 2, 6, 3, 7, 4, 8));

		fennec_test_spacer(1);

		fennec_test_run(fennec::transpose(mat4x3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)), mat3x4(1, 4, 7, 10, 2,  5, 8, 11,  3, 6, 9, 12));
		fennec_test_run(fennec::transpose(mat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)), mat4x3(1, 5, 9,  2, 6, 10, 3,  7, 11, 4, 8, 12));

		fennec_test_spacer(2);



		fennec_test_section("determinant");

		fennec_test_spacer(1);

		fennec_test_run(fennec::determinant(mat2(1, 2, 3, 4)),                                       -2.0f);
		fennec_test_run(fennec::determinant(mat3(1, 4, 8, 6, 2, 5, 9, 7, 3)),                         271.0f);
		fennec_test_run(fennec::determinant(mat4(2, 1, -3, 4, -1, 0, 2, 5, 3, 2, 1, 0, 4, -2, 3, 1)), 414.0f);

		fennec_test_spacer(2);



		fennec_test_section("inverse");

		fennec_test_spacer(1);

		fennec_test_run(fennec::inverse(mat2(1, 2, 3, 4)),                                                          mat2(-2, 1, 1.5, -0.5));
		fennec_test_run(fennec::inverse(mat3(1, 2, 3, 0, 1, 4, 5, 6, 0)),                                           mat3(-24, 18, 5, 20, -15, -4, -5, 4, 1));
		fennec_test_run(fennec::inverse(mat4(2, 1, -3, 4, -1, 0, 2, 5, 3, 2, 1, 0, 4, -2, 3, 1)), (1.0f / 414.0f) * mat4(36, -39, 33, 51, -18, 31, 133, -83, -72, 55, 49, 13, 36, 53, -13, 5));
	}

}

#endif // FENNEC_TEST_MATRIX_H
