// ok cpp include
#include "fl/math/geometry.h"
#include "test.h"
#include "fl/math/math.h"
#include "fl/stl/move.h"
#include "fl/stl/int.h"

using namespace fl;

FL_TEST_CASE("vec3::construction") {
    FL_SUBCASE("default constructor") {
        vec3<int> v;
        FL_CHECK_EQ(v.x, 0);
        FL_CHECK_EQ(v.y, 0);
        FL_CHECK_EQ(v.z, 0);
    }

    FL_SUBCASE("parameterized constructor") {
        vec3<int> v(1, 2, 3);
        FL_CHECK_EQ(v.x, 1);
        FL_CHECK_EQ(v.y, 2);
        FL_CHECK_EQ(v.z, 3);
    }

    FL_SUBCASE("uniform value constructor") {
        vec3<int> v(5);
        FL_CHECK_EQ(v.x, 5);
        FL_CHECK_EQ(v.y, 5);
        FL_CHECK_EQ(v.z, 5);
    }

    FL_SUBCASE("copy constructor") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(v1);
        FL_CHECK_EQ(v2.x, 1);
        FL_CHECK_EQ(v2.y, 2);
        FL_CHECK_EQ(v2.z, 3);
    }

    FL_SUBCASE("move constructor") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(fl::move(v1));
        FL_CHECK_EQ(v2.x, 1);
        FL_CHECK_EQ(v2.y, 2);
        FL_CHECK_EQ(v2.z, 3);
    }
}

FL_TEST_CASE("vec3::arithmetic_operators") {
    FL_SUBCASE("addition") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(4, 5, 6);
        vec3<int> result = v1 + v2;
        FL_CHECK_EQ(result.x, 5);
        FL_CHECK_EQ(result.y, 7);
        FL_CHECK_EQ(result.z, 9);
    }

    FL_SUBCASE("subtraction") {
        vec3<int> v1(5, 7, 9);
        vec3<int> v2(1, 2, 3);
        vec3<int> result = v1 - v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 5);
        FL_CHECK_EQ(result.z, 6);
    }

    FL_SUBCASE("multiplication") {
        vec3<int> v1(2, 3, 4);
        vec3<int> v2(2, 2, 2);
        vec3<int> result = v1 * v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 6);
        FL_CHECK_EQ(result.z, 8);
    }

    FL_SUBCASE("division") {
        vec3<int> v1(8, 12, 16);
        vec3<int> v2(2, 3, 4);
        vec3<int> result = v1 / v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 4);
        FL_CHECK_EQ(result.z, 4);
    }

    FL_SUBCASE("scalar multiplication") {
        vec3<int> v(2, 3, 4);
        vec3<int> result = v * 3;
        FL_CHECK_EQ(result.x, 6);
        FL_CHECK_EQ(result.y, 9);
        FL_CHECK_EQ(result.z, 12);
    }

    FL_SUBCASE("scalar division") {
        vec3<int> v(6, 9, 12);
        vec3<int> result = v / 3;
        FL_CHECK_EQ(result.x, 2);
        FL_CHECK_EQ(result.y, 3);
        FL_CHECK_EQ(result.z, 4);
    }

    FL_SUBCASE("scalar addition") {
        vec3<int> v(1, 2, 3);
        vec3<int> result = v + 5;
        FL_CHECK_EQ(result.x, 6);
        FL_CHECK_EQ(result.y, 7);
        FL_CHECK_EQ(result.z, 8);
    }

    FL_SUBCASE("scalar subtraction") {
        vec3<int> v(10, 20, 30);
        vec3<int> result = v - 5;
        FL_CHECK_EQ(result.x, 5);
        FL_CHECK_EQ(result.y, 15);
        FL_CHECK_EQ(result.z, 25);
    }
}

FL_TEST_CASE("vec3::compound_assignment_operators") {
    FL_SUBCASE("addition assignment") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(4, 5, 6);
        v1 += v2;
        FL_CHECK_EQ(v1.x, 5);
        FL_CHECK_EQ(v1.y, 7);
        FL_CHECK_EQ(v1.z, 9);
    }

    FL_SUBCASE("subtraction assignment") {
        vec3<int> v1(5, 7, 9);
        vec3<int> v2(1, 2, 3);
        v1 -= v2;
        FL_CHECK_EQ(v1.x, 4);
        FL_CHECK_EQ(v1.y, 5);
        FL_CHECK_EQ(v1.z, 6);
    }

    FL_SUBCASE("multiplication assignment with float") {
        vec3<float> v(2.0f, 3.0f, 4.0f);
        v *= 2.0f;
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 4.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 6.0f);
        FL_CHECK(doctest::Approx(v.z).epsilon(0.001) == 8.0f);
    }

    FL_SUBCASE("division assignment with float") {
        vec3<float> v(8.0f, 12.0f, 16.0f);
        v /= 2.0f;
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 4.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 6.0f);
        FL_CHECK(doctest::Approx(v.z).epsilon(0.001) == 8.0f);
    }

    FL_SUBCASE("division assignment with int") {
        vec3<int> v(8, 12, 16);
        v /= 2;
        FL_CHECK_EQ(v.x, 4);
        FL_CHECK_EQ(v.y, 6);
        FL_CHECK_EQ(v.z, 8);
    }

    FL_SUBCASE("division assignment with vec3") {
        vec3<int> v1(8, 12, 16);
        vec3<int> v2(2, 3, 4);
        v1 /= v2;
        FL_CHECK_EQ(v1.x, 4);
        FL_CHECK_EQ(v1.y, 4);
        FL_CHECK_EQ(v1.z, 4);
    }
}

FL_TEST_CASE("vec3::comparison_operators") {
    FL_SUBCASE("equality") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(1, 2, 3);
        vec3<int> v3(4, 5, 6);
        FL_CHECK(v1 == v2);
        FL_CHECK_FALSE(v1 == v3);
    }

    FL_SUBCASE("inequality") {
        vec3<int> v1(1, 2, 3);
        vec3<int> v2(1, 2, 3);
        vec3<int> v3(4, 5, 6);
        FL_CHECK_FALSE(v1 != v2);
        FL_CHECK(v1 != v3);
    }

    FL_SUBCASE("equality with different types") {
        vec3<int> v1(1, 2, 3);
        vec3<float> v2(1.0f, 2.0f, 3.0f);
        FL_CHECK(v1 == v2);
    }

    FL_SUBCASE("inequality with different types") {
        vec3<int> v1(1, 2, 3);
        vec3<float> v2(4.0f, 5.0f, 6.0f);
        FL_CHECK(v1 != v2);
    }
}

FL_TEST_CASE("vec3::utility_methods") {
    FL_SUBCASE("getMax") {
        vec3<int> v1(1, 5, 3);
        vec3<int> v2(4, 2, 6);
        vec3<int> result = v1.getMax(v2);
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 5);
        FL_CHECK_EQ(result.z, 6);
    }

    FL_SUBCASE("getMin") {
        vec3<int> v1(1, 5, 3);
        vec3<int> v2(4, 2, 6);
        vec3<int> result = v1.getMin(v2);
        FL_CHECK_EQ(result.x, 1);
        FL_CHECK_EQ(result.y, 2);
        FL_CHECK_EQ(result.z, 3);
    }

    FL_SUBCASE("cast") {
        vec3<int> v(1, 2, 3);
        vec3<float> result = v.cast<float>();
        FL_CHECK(doctest::Approx(result.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(result.y).epsilon(0.001) == 2.0f);
        FL_CHECK(doctest::Approx(result.z).epsilon(0.001) == 3.0f);
    }

    FL_SUBCASE("distance") {
        vec3<float> v1(0.0f, 0.0f, 0.0f);
        vec3<float> v2(3.0f, 4.0f, 0.0f);
        float dist = v1.distance(v2);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 5.0f);
    }

    FL_SUBCASE("is_zero") {
        vec3<int> v1(0, 0, 0);
        vec3<int> v2(1, 0, 0);
        FL_CHECK(v1.is_zero());
        FL_CHECK_FALSE(v2.is_zero());
    }
}

FL_TEST_CASE("vec2::construction") {
    FL_SUBCASE("default constructor") {
        vec2<int> v;
        FL_CHECK_EQ(v.x, 0);
        FL_CHECK_EQ(v.y, 0);
    }

    FL_SUBCASE("parameterized constructor") {
        vec2<int> v(1, 2);
        FL_CHECK_EQ(v.x, 1);
        FL_CHECK_EQ(v.y, 2);
    }

    FL_SUBCASE("uniform value constructor") {
        vec2<int> v(5);
        FL_CHECK_EQ(v.x, 5);
        FL_CHECK_EQ(v.y, 5);
    }

    FL_SUBCASE("copy constructor") {
        vec2<int> v1(1, 2);
        vec2<int> v2(v1);
        FL_CHECK_EQ(v2.x, 1);
        FL_CHECK_EQ(v2.y, 2);
    }

    FL_SUBCASE("move constructor") {
        vec2<int> v1(1, 2);
        vec2<int> v2(fl::move(v1));
        FL_CHECK_EQ(v2.x, 1);
        FL_CHECK_EQ(v2.y, 2);
    }
}

FL_TEST_CASE("vec2::arithmetic_operators") {
    FL_SUBCASE("addition") {
        vec2<int> v1(1, 2);
        vec2<int> v2(4, 5);
        vec2<int> result = v1 + v2;
        FL_CHECK_EQ(result.x, 5);
        FL_CHECK_EQ(result.y, 7);
    }

    FL_SUBCASE("subtraction") {
        vec2<int> v1(5, 7);
        vec2<int> v2(1, 2);
        vec2<int> result = v1 - v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 5);
    }

    FL_SUBCASE("multiplication") {
        vec2<int> v1(2, 3);
        vec2<int> v2(2, 2);
        vec2<int> result = v1 * v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 6);
    }

    FL_SUBCASE("division") {
        vec2<int> v1(8, 12);
        vec2<int> v2(2, 3);
        vec2<int> result = v1 / v2;
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 4);
    }

    FL_SUBCASE("scalar multiplication") {
        vec2<int> v(2, 3);
        vec2<int> result = v * 3;
        FL_CHECK_EQ(result.x, 6);
        FL_CHECK_EQ(result.y, 9);
    }

    FL_SUBCASE("scalar division") {
        vec2<int> v(6, 9);
        vec2<int> result = v / 3;
        FL_CHECK_EQ(result.x, 2);
        FL_CHECK_EQ(result.y, 3);
    }

    FL_SUBCASE("scalar addition") {
        vec2<int> v(1, 2);
        vec2<int> result = v + 5;
        FL_CHECK_EQ(result.x, 6);
        FL_CHECK_EQ(result.y, 7);
    }

    FL_SUBCASE("scalar subtraction") {
        vec2<int> v(10, 20);
        vec2<int> result = v - 5;
        FL_CHECK_EQ(result.x, 5);
        FL_CHECK_EQ(result.y, 15);
    }
}

FL_TEST_CASE("vec2::compound_assignment_operators") {
    FL_SUBCASE("addition assignment") {
        vec2<int> v1(1, 2);
        vec2<int> v2(4, 5);
        v1 += v2;
        FL_CHECK_EQ(v1.x, 5);
        FL_CHECK_EQ(v1.y, 7);
    }

    FL_SUBCASE("subtraction assignment") {
        vec2<int> v1(5, 7);
        vec2<int> v2(1, 2);
        v1 -= v2;
        FL_CHECK_EQ(v1.x, 4);
        FL_CHECK_EQ(v1.y, 5);
    }

    FL_SUBCASE("multiplication assignment with float") {
        vec2<float> v(2.0f, 3.0f);
        v *= 2.0f;
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 4.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 6.0f);
    }

    FL_SUBCASE("division assignment with float") {
        vec2<float> v(8.0f, 12.0f);
        v /= 2.0f;
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 4.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 6.0f);
    }

    FL_SUBCASE("division assignment with int") {
        vec2<int> v(8, 12);
        v /= 2;
        FL_CHECK_EQ(v.x, 4);
        FL_CHECK_EQ(v.y, 6);
    }

    FL_SUBCASE("division assignment with vec2") {
        vec2<int> v1(8, 12);
        vec2<int> v2(2, 3);
        v1 /= v2;
        FL_CHECK_EQ(v1.x, 4);
        FL_CHECK_EQ(v1.y, 4);
    }
}

FL_TEST_CASE("vec2::comparison_operators") {
    FL_SUBCASE("equality") {
        vec2<int> v1(1, 2);
        vec2<int> v2(1, 2);
        vec2<int> v3(4, 5);
        FL_CHECK(v1 == v2);
        FL_CHECK_FALSE(v1 == v3);
    }

    FL_SUBCASE("inequality") {
        vec2<int> v1(1, 2);
        vec2<int> v2(1, 2);
        vec2<int> v3(4, 5);
        FL_CHECK_FALSE(v1 != v2);
        FL_CHECK(v1 != v3);
    }

    FL_SUBCASE("equality with different types") {
        vec2<int> v1(1, 2);
        vec2<float> v2(1.0f, 2.0f);
        FL_CHECK(v1 == v2);
    }

    FL_SUBCASE("inequality with different types") {
        vec2<int> v1(1, 2);
        vec2<float> v2(4.0f, 5.0f);
        FL_CHECK(v1 != v2);
    }
}

FL_TEST_CASE("vec2::utility_methods") {
    FL_SUBCASE("getMax") {
        vec2<int> v1(1, 5);
        vec2<int> v2(4, 2);
        vec2<int> result = v1.getMax(v2);
        FL_CHECK_EQ(result.x, 4);
        FL_CHECK_EQ(result.y, 5);
    }

    FL_SUBCASE("getMin") {
        vec2<int> v1(1, 5);
        vec2<int> v2(4, 2);
        vec2<int> result = v1.getMin(v2);
        FL_CHECK_EQ(result.x, 1);
        FL_CHECK_EQ(result.y, 2);
    }

    FL_SUBCASE("cast") {
        vec2<int> v(1, 2);
        vec2<float> result = v.cast<float>();
        FL_CHECK(doctest::Approx(result.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(result.y).epsilon(0.001) == 2.0f);
    }

    FL_SUBCASE("distance") {
        vec2<float> v1(0.0f, 0.0f);
        vec2<float> v2(3.0f, 4.0f);
        float dist = v1.distance(v2);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 5.0f);
    }

    FL_SUBCASE("is_zero") {
        vec2<int> v1(0, 0);
        vec2<int> v2(1, 0);
        FL_CHECK(v1.is_zero());
        FL_CHECK_FALSE(v2.is_zero());
    }
}

FL_TEST_CASE("line_xy::construction") {
    FL_SUBCASE("default constructor") {
        line_xy<int> line;
        FL_CHECK_EQ(line.start.x, 0);
        FL_CHECK_EQ(line.start.y, 0);
        FL_CHECK_EQ(line.end.x, 0);
        FL_CHECK_EQ(line.end.y, 0);
    }

    FL_SUBCASE("vec2 constructor") {
        vec2<int> start(1, 2);
        vec2<int> end(3, 4);
        line_xy<int> line(start, end);
        FL_CHECK_EQ(line.start.x, 1);
        FL_CHECK_EQ(line.start.y, 2);
        FL_CHECK_EQ(line.end.x, 3);
        FL_CHECK_EQ(line.end.y, 4);
    }

    FL_SUBCASE("scalar constructor") {
        line_xy<int> line(1, 2, 3, 4);
        FL_CHECK_EQ(line.start.x, 1);
        FL_CHECK_EQ(line.start.y, 2);
        FL_CHECK_EQ(line.end.x, 3);
        FL_CHECK_EQ(line.end.y, 4);
    }

    FL_SUBCASE("copy constructor") {
        line_xy<int> line1(1, 2, 3, 4);
        line_xy<int> line2(line1);
        FL_CHECK_EQ(line2.start.x, 1);
        FL_CHECK_EQ(line2.start.y, 2);
        FL_CHECK_EQ(line2.end.x, 3);
        FL_CHECK_EQ(line2.end.y, 4);
    }
}

FL_TEST_CASE("line_xy::methods") {
    FL_SUBCASE("empty - true") {
        line_xy<int> line(1, 2, 1, 2);
        FL_CHECK(line.empty());
    }

    FL_SUBCASE("empty - false") {
        line_xy<int> line(1, 2, 3, 4);
        FL_CHECK_FALSE(line.empty());
    }

    FL_SUBCASE("distance_to - point on line") {
        line_xy<float> line(0.0f, 0.0f, 4.0f, 0.0f);
        vec2<float> p(2.0f, 0.0f);
        float dist = line.distance_to(p);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 0.0f);
    }

    FL_SUBCASE("distance_to - point perpendicular to line") {
        line_xy<float> line(0.0f, 0.0f, 4.0f, 0.0f);
        vec2<float> p(2.0f, 3.0f);
        float dist = line.distance_to(p);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 3.0f);
    }

    FL_SUBCASE("distance_to - point beyond line end") {
        line_xy<float> line(0.0f, 0.0f, 4.0f, 0.0f);
        vec2<float> p(6.0f, 3.0f);
        float dist = line.distance_to(p);
        // Distance from (6,3) to (4,0) = sqrt(4 + 9) = sqrt(13)
        FL_CHECK(doctest::Approx(dist).epsilon(0.01) == fl::sqrt(13.0f));
    }

    FL_SUBCASE("distance_to - with projected point output") {
        line_xy<float> line(0.0f, 0.0f, 4.0f, 0.0f);
        vec2<float> p(2.0f, 3.0f);
        vec2<float> projected;
        float dist = line.distance_to(p, &projected);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 3.0f);
        FL_CHECK(doctest::Approx(projected.x).epsilon(0.001) == 2.0f);
        FL_CHECK(doctest::Approx(projected.y).epsilon(0.001) == 0.0f);
    }

    FL_SUBCASE("distance_to - degenerate line (point)") {
        line_xy<float> line(1.0f, 1.0f, 1.0f, 1.0f);
        vec2<float> p(4.0f, 5.0f);
        float dist = line.distance_to(p);
        // Distance from (4,5) to (1,1) = sqrt(9 + 16) = 5
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 5.0f);
    }

    FL_SUBCASE("distance_to - origin on diagonal line") {
        line_xy<float> line(-100.0f, -100.0f, 100.0f, 100.0f);
        vec2<float> p(0.0f, 0.0f);
        vec2<float> projected;
        float dist = line.distance_to(p, &projected);
        FL_CHECK(doctest::Approx(projected.x).epsilon(0.001) == 0.0f);
        FL_CHECK(doctest::Approx(projected.y).epsilon(0.001) == 0.0f);
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 0.0f);
    }

    FL_SUBCASE("distance_to - point closest to diagonal line") {
        line_xy<float> line(-100.0f, -100.0f, 100.0f, 100.0f);
        vec2<float> p(50.0f, 0.0f);
        vec2<float> projected;
        float dist = line.distance_to(p, &projected);
        // The closest point should be (25, 25)
        FL_CHECK(doctest::Approx(projected.x).epsilon(0.001) == 25.0f);
        FL_CHECK(doctest::Approx(projected.y).epsilon(0.001) == 25.0f);
        // Distance should be sqrt((50-25)^2 + (0-25)^2) = sqrt(1250) ≈ 35.355
        FL_CHECK(doctest::Approx(dist).epsilon(0.001) == 35.355f);
    }
}

FL_TEST_CASE("rect::construction") {
    FL_SUBCASE("default constructor") {
        rect<int> r;
        FL_CHECK_EQ(r.mMin.x, 0);
        FL_CHECK_EQ(r.mMin.y, 0);
        FL_CHECK_EQ(r.mMax.x, 0);
        FL_CHECK_EQ(r.mMax.y, 0);
    }

    FL_SUBCASE("vec2 constructor") {
        vec2<int> min(1, 2);
        vec2<int> max(5, 7);
        rect<int> r(min, max);
        FL_CHECK_EQ(r.mMin.x, 1);
        FL_CHECK_EQ(r.mMin.y, 2);
        FL_CHECK_EQ(r.mMax.x, 5);
        FL_CHECK_EQ(r.mMax.y, 7);
    }

    FL_SUBCASE("scalar constructor") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK_EQ(r.mMin.x, 1);
        FL_CHECK_EQ(r.mMin.y, 2);
        FL_CHECK_EQ(r.mMax.x, 5);
        FL_CHECK_EQ(r.mMax.y, 7);
    }

    FL_SUBCASE("copy constructor") {
        rect<int> r1(1, 2, 5, 7);
        rect<int> r2(r1);
        FL_CHECK_EQ(r2.mMin.x, 1);
        FL_CHECK_EQ(r2.mMin.y, 2);
        FL_CHECK_EQ(r2.mMax.x, 5);
        FL_CHECK_EQ(r2.mMax.y, 7);
    }
}

FL_TEST_CASE("rect::dimensions") {
    FL_SUBCASE("width") {
        rect<u16> r(1, 2, 10, 7);
        FL_CHECK_EQ(r.width(), 9);
    }

    FL_SUBCASE("height") {
        rect<u16> r(1, 2, 10, 7);
        FL_CHECK_EQ(r.height(), 5);
    }

    FL_SUBCASE("empty - true") {
        rect<int> r(1, 2, 1, 2);
        FL_CHECK(r.empty());
    }

    FL_SUBCASE("empty - false") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK_FALSE(r.empty());
    }
}

FL_TEST_CASE("rect::expand") {
    FL_SUBCASE("expand with point") {
        rect<int> r(1, 2, 5, 7);
        r.expand(vec2<int>(0, 10));
        FL_CHECK_EQ(r.mMin.x, 0);
        FL_CHECK_EQ(r.mMin.y, 2);
        FL_CHECK_EQ(r.mMax.x, 5);
        FL_CHECK_EQ(r.mMax.y, 10);
    }

    FL_SUBCASE("expand with coordinates") {
        rect<int> r(1, 2, 5, 7);
        r.expand(6, 1);
        FL_CHECK_EQ(r.mMin.x, 1);
        FL_CHECK_EQ(r.mMin.y, 1);
        FL_CHECK_EQ(r.mMax.x, 6);
        FL_CHECK_EQ(r.mMax.y, 7);
    }

    FL_SUBCASE("expand with another rect") {
        rect<int> r1(1, 2, 5, 7);
        rect<int> r2(0, 8, 6, 10);
        r1.expand(r2);
        FL_CHECK_EQ(r1.mMin.x, 0);
        FL_CHECK_EQ(r1.mMin.y, 2);
        FL_CHECK_EQ(r1.mMax.x, 6);
        FL_CHECK_EQ(r1.mMax.y, 10);
    }
}

FL_TEST_CASE("rect::contains") {
    FL_SUBCASE("contains point - inside") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK(r.contains(vec2<int>(3, 4)));
    }

    FL_SUBCASE("contains point - outside") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK_FALSE(r.contains(vec2<int>(6, 4)));
        FL_CHECK_FALSE(r.contains(vec2<int>(0, 4)));
        FL_CHECK_FALSE(r.contains(vec2<int>(3, 8)));
        FL_CHECK_FALSE(r.contains(vec2<int>(3, 1)));
    }

    FL_SUBCASE("contains point - on edge (min)") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK(r.contains(vec2<int>(1, 2)));
    }

    FL_SUBCASE("contains point - on edge (max)") {
        rect<int> r(1, 2, 5, 7);
        // Max is exclusive based on the contains logic
        FL_CHECK_FALSE(r.contains(vec2<int>(5, 7)));
    }

    FL_SUBCASE("contains coordinates") {
        rect<int> r(1, 2, 5, 7);
        FL_CHECK(r.contains(3, 4));
        FL_CHECK_FALSE(r.contains(6, 4));
    }
}

FL_TEST_CASE("rect::comparison_operators") {
    FL_SUBCASE("equality") {
        rect<int> r1(1, 2, 5, 7);
        rect<int> r2(1, 2, 5, 7);
        rect<int> r3(0, 0, 10, 10);
        FL_CHECK(r1 == r2);
        FL_CHECK_FALSE(r1 == r3);
    }

    FL_SUBCASE("inequality") {
        rect<int> r1(1, 2, 5, 7);
        rect<int> r2(1, 2, 5, 7);
        rect<int> r3(0, 0, 10, 10);
        FL_CHECK_FALSE(r1 != r2);
        FL_CHECK(r1 != r3);
    }

    FL_SUBCASE("equality with different types") {
        rect<int> r1(1, 2, 5, 7);
        rect<float> r2(1.0f, 2.0f, 5.0f, 7.0f);
        FL_CHECK(r1 == r2);
    }

    FL_SUBCASE("inequality with different types") {
        rect<int> r1(1, 2, 5, 7);
        rect<float> r2(0.0f, 0.0f, 10.0f, 10.0f);
        FL_CHECK(r1 != r2);
    }
}

FL_TEST_CASE("type_aliases") {
    FL_SUBCASE("vec3f") {
        vec3f v(1.0f, 2.0f, 3.0f);
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 2.0f);
        FL_CHECK(doctest::Approx(v.z).epsilon(0.001) == 3.0f);
    }

    FL_SUBCASE("vec2f") {
        vec2f v(1.0f, 2.0f);
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 2.0f);
    }

    FL_SUBCASE("vec2u8") {
        vec2u8 v(1, 2);
        FL_CHECK_EQ(v.x, 1);
        FL_CHECK_EQ(v.y, 2);
    }

    FL_SUBCASE("vec2i16") {
        vec2i16 v(-100, 200);
        FL_CHECK_EQ(v.x, -100);
        FL_CHECK_EQ(v.y, 200);
    }

    FL_SUBCASE("pair_xyz_float") {
        pair_xyz_float v(1.0f, 2.0f, 3.0f);
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 2.0f);
        FL_CHECK(doctest::Approx(v.z).epsilon(0.001) == 3.0f);
    }

    FL_SUBCASE("pair_xy_float") {
        pair_xy_float v(1.0f, 2.0f);
        FL_CHECK(doctest::Approx(v.x).epsilon(0.001) == 1.0f);
        FL_CHECK(doctest::Approx(v.y).epsilon(0.001) == 2.0f);
    }

    FL_SUBCASE("pair_xy") {
        pair_xy<int> v(1, 2);
        FL_CHECK_EQ(v.x, 1);
        FL_CHECK_EQ(v.y, 2);

        // Test that pair_xy can be constructed from vec2
        vec2<int> v2(3, 4);
        pair_xy<int> p(v2);
        FL_CHECK_EQ(p.x, 3);
        FL_CHECK_EQ(p.y, 4);
    }
}

FL_TEST_CASE("vec3::cross_type_operations") {
    FL_SUBCASE("addition with different types") {
        vec3<int> v1(1, 2, 3);
        vec3<float> v2(1.5f, 2.5f, 3.5f);
        vec3<int> result = v1 + v2;
        FL_CHECK_EQ(result.x, 2);
        FL_CHECK_EQ(result.y, 4);
        FL_CHECK_EQ(result.z, 6);
    }
}

FL_TEST_CASE("vec2::cross_type_operations") {
    FL_SUBCASE("addition with different types") {
        vec2<int> v1(1, 2);
        vec2<float> v2(1.5f, 2.5f);
        vec2<int> result = v1 + v2;
        FL_CHECK_EQ(result.x, 2);
        // Note: There's a bug in the header at line 279: return vec2(x + p.x, y + p.x);
        // It should be: return vec2(x + p.x, y + p.y);
        // So this test will expose that bug
        FL_CHECK_EQ(result.y, 3);  // This will likely fail due to the bug
    }
}

// Grouped tests
#include "tests/fl/math/grid.hpp"
#include "tests/fl/gfx/tile2x2.hpp"
#include "tests/fl/math/traverse_grid.hpp"

FL_TEST_FILE(FL_FILEPATH) {

} // FL_TEST_FILE
