
#include <pw/core/serialize.hpp>
#include <pw/core/vector.hpp>

#include <print>
#include <tuple>
#include <vector>

auto main() -> int {

    auto v2_A = pw::vector{3.2, 1.2};
    auto v2_B = pw::vector{6.4, 2.4};

    auto AB_lerp = decltype(v2_A)::lerp(v2_A, v2_B, 0.5);

    std::print("lerp A:({}) B:({}) t:({}) -> {}\n",
               pw::serialize::to_string(v2_A), pw::serialize::to_string(v2_B),
               0.5, pw::serialize::to_string(AB_lerp));

    auto v4_14 = pw::vector4<float>::all(1.4);
    auto v4_sq = pw::vector4<float>::sequence(1.4);
    auto v3_fw = pw::vector3f::forward();

    std::print("all(1.4) -> {}\n", pw::serialize::to_string(v4_14));
    std::print("sequence(1.4) -> {}\n", pw::serialize::to_string(v4_sq));
    std::print("forward() -> {}\n", pw::serialize::to_string(v3_fw));

    auto v3_sw_1 = v4_sq.swizzle(0, 1); // xy
    auto v3_sw_2 = v4_sq.swizzle(1, 0); // yx
    auto v3_sw_3 = v4_sq.swizzle(0, 2); // xz

    std::print("swizzle(0,1) aka xy -> {}\n",
               pw::serialize::to_string(v3_sw_1));
    std::print("swizzle(1,0) aka yx -> {}\n",
               pw::serialize::to_string(v3_sw_2));
    std::print("swizzle(0,2) aka xz -> {}\n",
               pw::serialize::to_string(v3_sw_3));

    auto v3_up_1 = v3_fw.unproject(1);
    auto v3_pj_1 = v3_up_1.project();

    std::print("unproject(1) -> {}\n", pw::serialize::to_string(v3_up_1));
    std::print("project() -> {}\n", pw::serialize::to_string(v3_pj_1));

    auto v3_nlz = v3_up_1.normalized();
    std::print("normalized() -> {}\n", pw::serialize::to_string(v3_nlz));

    auto e1 = pw::vector{2.0, 0.0, 0.0};
    auto e2 = pw::vector{0.0, 0.0, 2.0};

    auto e2_e1 = e1 - e2;

    std::print("{} - {} -> {}\n", pw::serialize::to_string(e1),
               pw::serialize::to_string(e2), pw::serialize::to_string(e2_e1));

    auto e1_cross_e2 = e1.cross(e2);
    std::print("{} x {} -> {}\n", pw::serialize::to_string(e1),
               pw::serialize::to_string(e2),
               pw::serialize::to_string(e1_cross_e2));

    auto e1_dot_e2 = e1.dot(e2);

    std::print("{} * {} -> {}\n", pw::serialize::to_string(e1),
               pw::serialize::to_string(e2), e1_dot_e2);

    auto vec3f = pw::vector{1.f, 2.f, 3.f};

    std::print("y: {}\n", vec3f.get<1>());
    std::print("tuple size {}\n", std::tuple_size_v<decltype(vec3f)>);

    auto& [x, y, z] = vec3f;
    std::print("x:{} y:{} z:{}\n", x, y, z);

    auto min_ab{vec3f.min(pw::vector{1.3f, 0.9f, 2.3f})};

    std::print("min((1.3f,0.9f,2.3f),({} {} {})) -> ({} {} {})\n", vec3f.x(),
               vec3f.y(), vec3f.z(), min_ab.x(), min_ab.y(), min_ab.z());

    return 0;
}
