// =====================================================================================================================
//  fennec, a free and open source game engine
//  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_MATH_COMMON_H
#define FENNEC_TEST_MATH_COMMON_H

#include "../../test.h"

namespace fennec::test
{

	inline void fennec_test_math_common()
	{
		fennec_test_section("Sign Functions");

		fennec_test_spacer(1);

		fennec_test_run(fennec::abs( 1), 1);
		fennec_test_run(fennec::abs(-1), 1);
		fennec_test_run(fennec::abs( 1.0f), 1.0f);
		fennec_test_run(fennec::abs(-1.0f), 1.0f);
		fennec_test_run(fennec::abs( 1.0), 1.0);
		fennec_test_run(fennec::abs(-1.0), 1.0);

		fennec_test_run(fennec::abs(vec2(1.0f, -1.0f)), vec2(1.0f));

		fennec_test_spacer(1);

		fennec_test_run(fennec::sign(vec2( 1, -2)),         vec2( 1, -1));
		fennec_test_run(fennec::sign(vec3(-1,  2, -3)),     vec3(-1,  1, -1));
		fennec_test_run(fennec::sign(vec4( 1, -2,  3, -4)), vec4( 1, -1,  1, -1));

		fennec_test_spacer(2);



		fennec_test_section("Rounding Functions");

		fennec_test_spacer(1);

		fennec_test_run(fennec::ceil(2.4f), 3.0f);
		fennec_test_run(fennec::ceil(2.5f), 3.0f);
		fennec_test_run(fennec::ceil(2.6f), 3.0f);

		fennec_test_run(fennec::ceil(-2.4f), -2.0f);
		fennec_test_run(fennec::ceil(-2.5f), -2.0f);
		fennec_test_run(fennec::ceil(-2.6f), -2.0f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::floor(2.4f), 2.0f);
		fennec_test_run(fennec::floor(2.5f), 2.0f);
		fennec_test_run(fennec::floor(2.6f), 2.0f);

		fennec_test_run(fennec::floor(-2.4f), -3.0f);
		fennec_test_run(fennec::floor(-2.5f), -3.0f);
		fennec_test_run(fennec::floor(-2.6f), -3.0f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::round(2.4f),     2.0f);
		fennec_test_run(fennec::round(2.5f),     3.0f);
		fennec_test_run(fennec::round(2.6f),     3.0f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::roundEven(2.4f), 2.0f);
		fennec_test_run(fennec::roundEven(2.5f), 2.0f);
		fennec_test_run(fennec::roundEven(2.6f), 3.0f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::trunc(2.4f), 2.0f);
		fennec_test_run(fennec::trunc(2.5f), 2.0f);
		fennec_test_run(fennec::trunc(2.6f), 2.0f);

		fennec_test_run(fennec::trunc(-2.4f), -2.0f);
		fennec_test_run(fennec::trunc(-2.5f), -2.0f);
		fennec_test_run(fennec::trunc(-2.6f), -2.0f);

		fennec_test_spacer(2);



		fennec_test_section("Floating Point Functions");

		fennec_test_spacer(1);

		fennec_test_run(fennec::fract(2.4f), 0.4f);
		fennec_test_run(fennec::fract(2.5f), 0.5f);
		fennec_test_run(fennec::fract(2.6f), 0.6f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::mod(2.4f, 2.0f), 0.4f);
		fennec_test_run(fennec::mod(2.5f, 2.0f), 0.5f);
		fennec_test_run(fennec::mod(2.6f, 2.0f), 0.6f);

		fennec_test_spacer(1);

		fennec_test_run([]() -> float { float i; return fennec::modf(2.4f, i) + i; }(), 2.4f);
		fennec_test_run([]() -> float { float i; return fennec::modf(2.5f, i) + i; }(), 2.5f);
		fennec_test_run([]() -> float { float i; return fennec::modf(2.6f, i) + i; }(), 2.6f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::isnan(0.0f), false);
		fennec_test_run(fennec::isnan(fennec::numeric_limits<float>::quiet_NaN()), true);
		fennec_test_run(fennec::isnan(fennec::numeric_limits<float>::signaling_NaN()), true);

		fennec_test_spacer(1);

		fennec_test_run(fennec::isinf( 0.0f), false);
		fennec_test_run(fennec::isinf( fennec::numeric_limits<float>::infinity()), true);
		fennec_test_run(fennec::isinf(-fennec::numeric_limits<float>::infinity()), true);

		fennec_test_spacer(1);

		fennec_test_run(fennec::floatBitsToInt( 1.0f), static_cast<int>(0x3f800000u));
		fennec_test_run(fennec::floatBitsToInt(-1.0f), static_cast<int>(0xbf800000u));
		fennec_test_run(fennec::floatBitsToUint( 1.0f), 0x3f800000u);
		fennec_test_run(fennec::floatBitsToUint(-1.0f), 0xbf800000u);

		fennec_test_spacer(1);

		fennec_test_run(fennec::intBitsToFloat(static_cast<int>(0x3f800000u)),  1.0f);
		fennec_test_run(fennec::intBitsToFloat(static_cast<int>(0xbf800000u)), -1.0f);
		fennec_test_run(fennec::uintBitsToFloat(0x3f800000u),  1.0f);
		fennec_test_run(fennec::uintBitsToFloat(0xbf800000u), -1.0f);

		fennec_test_spacer(1);

		fennec_test_run(fennec::fma( 1,  2,  3),  5);
		fennec_test_run(fennec::fma(-1,  2, -3), -5);
		fennec_test_run(fennec::fma( 1, -2,  3),  1);

		fennec_test_spacer(1);

		fennec_test_run([]() -> float { int i; const float f = fennec::frexp(2.4f, i); return fennec::ldexp(f, i); }(), 2.4f);
		fennec_test_run([]() -> float { int i; const float f = fennec::frexp(2.5f, i); return fennec::ldexp(f, i); }(), 2.5f);
		fennec_test_run([]() -> float { int i; const float f = fennec::frexp(2.6f, i); return fennec::ldexp(f, i); }(), 2.6f);

		fennec_test_spacer(2);



		fennec_test_section("Comparison Functions");

		fennec_test_spacer(1);

		fennec_test_run(min(2.0f, 1.0f), 1.0f);
		fennec_test_run(min(-fennec::numeric_limits<float>::infinity(), 0.0f), -fennec::numeric_limits<float>::infinity());

		fennec_test_spacer(1);

		fennec_test_run(max(2.0f, 1.0f), 2.0f);
		fennec_test_run(max(-fennec::numeric_limits<float>::infinity(), 0.0f),  0.0f);

		fennec_test_spacer(1);

		fennec_test_run(clamp(-0.5f, 0.0f, 1.0f),  0.0f);
		fennec_test_run(clamp( 0.5f, 0.0f, 1.0f),  0.5f);
		fennec_test_run(clamp( 1.5f, 0.0f, 1.0f),  1.0f);

		fennec_test_spacer(2);



		fennec_test_section("Curves");

		fennec_test_spacer(1);

		fennec_test_run(step(2.5f, 2.4f), 0.0f);
		fennec_test_run(step(2.5f, 2.5f), 1.0f);
		fennec_test_run(step(2.5f, 2.6f), 1.0f);

		fennec_test_spacer(1);

		fennec_test_run(smoothstep(0.0f, 1.0f, -0.5f), 0.0f);
		fennec_test_run(smoothstep(0.0f, 1.0f,  0.5f), 0.5f);
		fennec_test_run(smoothstep(0.0f, 1.0f,  1.5f), 1.0f);

		fennec_test_spacer(1);

		fennec_test_run(mix(0.0f, 1.0f, -0.5f), -0.5f);
		fennec_test_run(mix(0.0f, 1.0f,  0.5f),  0.5f);
		fennec_test_run(mix(0.0f, 1.0f,  1.5f),  1.5f);

		fennec_test_spacer(1);

		fennec_test_run(mix(0.0f, 1.0f, false), 0.0f);
		fennec_test_run(mix(0.0f, 1.0f, true),  1.0f);
	}

}

#endif // FENNEC_TEST_MATH_COMMON_H
