#pragma once

// math2d — primitive 2D types used across gamedev stack (issue 0072b).
// Pure value types. No allocations, no virtual, trivial copy.

#include <cmath>

namespace fn::math2d {

struct Vec2 {
    float x = 0.0f;
    float y = 0.0f;

    constexpr Vec2() = default;
    constexpr Vec2(float xv, float yv) : x(xv), y(yv) {}

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

    float length() const { return std::sqrt(x * x + y * y); }
    constexpr float length_sq() const { return x * x + y * y; }
    Vec2 normalized() const {
        float l = length();
        return l > 0.0f ? Vec2{x / l, y / l} : Vec2{0.0f, 0.0f};
    }
    static constexpr float dot(Vec2 a, Vec2 b) { return a.x * b.x + a.y * b.y; }
    static constexpr float cross(Vec2 a, Vec2 b) { return a.x * b.y - a.y * b.x; }
};

struct Rect {
    float x = 0.0f;
    float y = 0.0f;
    float w = 0.0f;
    float h = 0.0f;

    constexpr Rect() = default;
    constexpr Rect(float xv, float yv, float wv, float hv) : x(xv), y(yv), w(wv), h(hv) {}

    constexpr float right() const { return x + w; }
    constexpr float bottom() const { return y + h; }
    constexpr Vec2 center() const { return {x + w * 0.5f, y + h * 0.5f}; }
    constexpr Vec2 min() const { return {x, y}; }
    constexpr Vec2 max() const { return {x + w, y + h}; }

    constexpr bool contains(Vec2 p) const {
        return p.x >= x && p.x < x + w && p.y >= y && p.y < y + h;
    }
    constexpr bool overlaps(Rect b) const {
        return !(b.x >= x + w || b.x + b.w <= x ||
                 b.y >= y + h || b.y + b.h <= y);
    }
};

struct Color {
    float r = 1.0f;
    float g = 1.0f;
    float b = 1.0f;
    float a = 1.0f;

    constexpr Color() = default;
    constexpr Color(float rv, float gv, float bv, float av = 1.0f)
        : r(rv), g(gv), b(bv), a(av) {}

    static constexpr Color white()       { return {1, 1, 1, 1}; }
    static constexpr Color black()       { return {0, 0, 0, 1}; }
    static constexpr Color transparent() { return {0, 0, 0, 0}; }

    static Color rgba(unsigned char r8, unsigned char g8, unsigned char b8,
                      unsigned char a8 = 255) {
        return {r8 / 255.0f, g8 / 255.0f, b8 / 255.0f, a8 / 255.0f};
    }
    static Color hex(unsigned int packed) {
        return Color::rgba((packed >> 24) & 0xFF, (packed >> 16) & 0xFF,
                           (packed >> 8) & 0xFF, packed & 0xFF);
    }
};

}  // namespace fn::math2d
