#pragma once
#include <windows.h>

namespace rbx {
	struct vector2_t {
		float x, y;

		vector2_t() : x(0.f), y(0.f) {}
		vector2_t(float x, float y) : x(x), y(y) {}

		vector2_t operator+(const vector2_t& other) const {
			return vector2_t(x + other.x, y + other.y);
		}

		vector2_t operator-(const vector2_t& other) const {
			return vector2_t(x - other.x, y - other.y);
		}

		vector2_t operator*(float scalar) const {
			return vector2_t(x * scalar, y * scalar);
		}

		vector2_t operator/(float scalar) const {
			return vector2_t(x / scalar, y / scalar);
		}

		vector2_t& operator+=(const vector2_t& other) {
			x += other.x;
			y += other.y;
			return *this;
		}

		vector2_t& operator-=(const vector2_t& other) {
			x -= other.x;
			y -= other.y;
			return *this;
		}

		vector2_t& operator*=(float scalar) {
			x *= scalar;
			y *= scalar;
			return *this;
		}

		vector2_t& operator/=(float scalar) {
			x /= scalar;
			y /= scalar;
			return *this;
		}

		float dot(const vector2_t& other) const {
			return x * other.x + y * other.y;
		}

		float magnitude() const {
			return sqrtf(x * x + y * y);
		}

		vector2_t normalize() const {
			float mag = magnitude();
			return mag > 0.f ? *this * (1.f / mag) : vector2_t(0.f, 0.f);
		}

		float distance(const vector2_t& other) const {
			float dx = x - other.x;
			float dy = y - other.y;
			return sqrtf(dx * dx + dy * dy);
		}

		vector2_t lerp(const vector2_t& other, float t) const {
			return *this + (other - *this) * t;
		}
	};

	struct vector3_t {
		float x, y, z;

		vector3_t() : x(0.f), y(0.f), z(0.f) {}
		vector3_t(float x, float y, float z) : x(x), y(y), z(z) {}

		vector3_t operator+(const vector3_t& other) const {
			return vector3_t(x + other.x, y + other.y, z + other.z);
		}

		vector3_t operator-(const vector3_t& other) const {
			return vector3_t(x - other.x, y - other.y, z - other.z);
		}

		vector3_t operator*(float scalar) const {
			return vector3_t(x * scalar, y * scalar, z * scalar);
		}

		vector3_t operator/(float scalar) const {
			return vector3_t(x / scalar, y / scalar, z / scalar);
		}

		vector3_t& operator+=(const vector3_t& other) {
			x += other.x;
			y += other.y;
			z += other.z;
			return *this;
		}

		vector3_t& operator-=(const vector3_t& other) {
			x -= other.x;
			y -= other.y;
			z -= other.z;
			return *this;
		}

		vector3_t& operator*=(float scalar) {
			x *= scalar;
			y *= scalar;
			z *= scalar;
			return *this;
		}

		vector3_t& operator/=(float scalar) {
			x /= scalar;
			y /= scalar;
			z /= scalar;
			return *this;
		}

		float dot(const vector3_t& other) const {
			return x * other.x + y * other.y + z * other.z;
		}

		vector3_t cross(const vector3_t& other) const {
			return vector3_t(
				y * other.z - z * other.y,
				z * other.x - x * other.z,
				x * other.y - y * other.x
			);
		}

		float magnitude() const {
			return sqrtf(x * x + y * y + z * z);
		}

		vector3_t normalize() const {
			float mag = magnitude();
			return mag > 0.f ? *this * (1.f / mag) : vector3_t(0.f, 0.f, 0.f);
		}

		float distance(const vector3_t& other) const {
			float dx = x - other.x;
			float dy = y - other.y;
			float dz = z - other.z;
			return sqrtf(dx * dx + dy * dy + dz * dz);
		}

		vector3_t lerp(const vector3_t& other, float t) const {
			return *this + (other - *this) * t;
		}
	};

	struct vector4_t {
		float x, y, z, w;

		vector4_t() : x(0.f), y(0.f), z(0.f), w(0.f) {}
		vector4_t(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}

		vector4_t operator+(const vector4_t& other) const {
			return vector4_t(x + other.x, y + other.y, z + other.z, w + other.w);
		}

		vector4_t operator-(const vector4_t& other) const {
			return vector4_t(x - other.x, y - other.y, z - other.z, w - other.w);
		}

		vector4_t operator*(float scalar) const {
			return vector4_t(x * scalar, y * scalar, z * scalar, w * scalar);
		}

		vector4_t operator/(float scalar) const {
			return vector4_t(x / scalar, y / scalar, z / scalar, w / scalar);
		}

		vector4_t& operator+=(const vector4_t& other) {
			x += other.x;
			y += other.y;
			z += other.z;
			w += other.w;
			return *this;
		}

		vector4_t& operator-=(const vector4_t& other) {
			x -= other.x;
			y -= other.y;
			z -= other.z;
			w -= other.w;
			return *this;
		}

		vector4_t& operator*=(float scalar) {
			x *= scalar;
			y *= scalar;
			z *= scalar;
			w *= scalar;
			return *this;
		}

		vector4_t& operator/=(float scalar) {
			x /= scalar;
			y /= scalar;
			z /= scalar;
			w /= scalar;
			return *this;
		}

		float dot(const vector4_t& other) const {
			return x * other.x + y * other.y + z * other.z + w * other.w;
		}

		float magnitude() const {
			return sqrtf(x * x + y * y + z * z + w * w);
		}

		vector4_t normalize() const {
			float mag = magnitude();
			return mag > 0.f ? *this * (1.f / mag) : vector4_t(0.f, 0.f, 0.f, 0.f);
		}

		float distance(const vector4_t& other) const {
			float dx = x - other.x;
			float dy = y - other.y;
			float dz = z - other.z;
			float dw = w - other.w;
			return sqrtf(dx * dx + dy * dy + dz * dz + dw * dw);
		}

		vector4_t lerp(const vector4_t& other, float t) const {
			return *this + (other - *this) * t;
		}
	};

	struct matrix3_t {
		float data[9];

		matrix3_t() {
			for (int i = 0; i < 9; ++i) data[i] = 0.f;
		}

		matrix3_t operator+(const matrix3_t& other) const {
			matrix3_t result;
			for (int i = 0; i < 9; ++i) result.data[i] = data[i] + other.data[i];
			return result;
		}

		matrix3_t operator-(const matrix3_t& other) const {
			matrix3_t result;
			for (int i = 0; i < 9; ++i) result.data[i] = data[i] - other.data[i];
			return result;
		}

		matrix3_t operator*(const matrix3_t& other) const {
			matrix3_t result;
			for (int i = 0; i < 3; ++i)
				for (int j = 0; j < 3; ++j)
					for (int k = 0; k < 3; ++k)
						result.data[i * 3 + j] += data[i * 3 + k] * other.data[k * 3 + j];
			return result;
		}

		matrix3_t operator*(float scalar) const {
			matrix3_t result;
			for (int i = 0; i < 9; ++i) result.data[i] = data[i] * scalar;
			return result;
		}

		matrix3_t lerp(const matrix3_t& other, float t) const {
			matrix3_t res;
			for (int i = 0; i < 9; ++i) {
				res.data[i] = data[i] + (other.data[i] - data[i]) * t;
			}
			return res;
		}

		matrix3_t lerp_smooth(const matrix3_t& other, float x, float y) const {
			matrix3_t res;
			for (int i = 0; i < 9; ++i) {
				if (i % 3 == 0)
					res.data[i] = data[i] + (other.data[i] - data[i]) * x;
				else
					res.data[i] = data[i] + (other.data[i] - data[i]) * y;
			}
			return res;
		}
	};

	struct matrix4_t {
		float data[16];

		matrix4_t() {
			for (int i = 0; i < 16; ++i) data[i] = 0.f;
		}

		matrix4_t operator+(const matrix4_t& other) const {
			matrix4_t result;
			for (int i = 0; i < 16; ++i) result.data[i] = data[i] + other.data[i];
			return result;
		}

		matrix4_t operator-(const matrix4_t& other) const {
			matrix4_t result;
			for (int i = 0; i < 16; ++i) result.data[i] = data[i] - other.data[i];
			return result;
		}

		matrix4_t operator*(const matrix4_t& other) const {
			matrix4_t result;
			for (int i = 0; i < 4; ++i)
				for (int j = 0; j < 4; ++j)
					for (int k = 0; k < 4; ++k)
						result.data[i * 4 + j] += data[i * 4 + k] * other.data[k * 4 + j];
			return result;
		}

		matrix4_t operator*(float scalar) const {
			matrix4_t result;
			for (int i = 0; i < 16; ++i) result.data[i] = data[i] * scalar;
			return result;
		}
	};
}