// types.hpp - Tipos básicos compartidos
// © 2025 Orni Attack

#pragma once

#include <cmath>

// Vector 2D cartesiano - única estructura de coordenadas del juego.
// Aggregate (sin constructores definidos) para soportar designated initializers:
//     Vec2{.x = 1.0F, .y = 2.0F}
// y aggregate initialization clásica:
//     Vec2{1.0F, 2.0F}
struct Vec2 {
        float x{0.0F};
        float y{0.0F};

        constexpr auto operator+=(const Vec2& o) -> Vec2& {
            x += o.x;
            y += o.y;
            return *this;
        }
        constexpr auto operator-=(const Vec2& o) -> Vec2& {
            x -= o.x;
            y -= o.y;
            return *this;
        }
        constexpr auto operator*=(float s) -> Vec2& {
            x *= s;
            y *= s;
            return *this;
        }
        constexpr auto operator/=(float s) -> Vec2& {
            x /= s;
            y /= s;
            return *this;
        }

        [[nodiscard]] auto lengthSquared() const -> float { return (x * x) + (y * y); }
        [[nodiscard]] auto length() const -> float { return std::sqrt(lengthSquared()); }
        [[nodiscard]] auto dot(const Vec2& o) const -> float { return (x * o.x) + (y * o.y); }

        // Devuelve el vector normalizado; si la magnitud es 0 devuelve {0,0}.
        [[nodiscard]] auto normalized() const -> Vec2 {
            const float L = length();
            return L > 0.0F ? Vec2{.x = x / L, .y = y / L} : Vec2{};
        }
};

constexpr auto operator+(Vec2 a, const Vec2& b) -> Vec2 {
    a += b;
    return a;
}
constexpr auto operator-(Vec2 a, const Vec2& b) -> Vec2 {
    a -= b;
    return a;
}
constexpr auto operator*(Vec2 v, float s) -> Vec2 {
    v *= s;
    return v;
}
constexpr auto operator*(float s, Vec2 v) -> Vec2 {
    v *= s;
    return v;
}
constexpr auto operator/(Vec2 v, float s) -> Vec2 {
    v /= s;
    return v;
}
constexpr auto operator-(const Vec2& v) -> Vec2 { return {.x = -v.x, .y = -v.y}; }
constexpr auto operator==(const Vec2& a, const Vec2& b) -> bool {
    return a.x == b.x && a.y == b.y;
}
